Introduction
In the Context7 API documentation repository, we discovered a high-severity security issue in docs/api-guide.mdx at line 67. The "Complete Workflow Example" section contained a Python code snippet that demonstrated API authentication using a hardcoded string "Bearer CONTEXT7_API_KEY" instead of showing developers the proper pattern for loading credentials from environment variables. While this may seem like an innocent documentation example, it creates a dangerous copy-paste vulnerability where developers implementing the API might use this exact code in production without realizing they need to replace the placeholder with actual credential management.
The vulnerability was flagged by the multi_agent_ai scanner using rule V-001, which identified that the documentation pattern could lead to credential exposure in downstream applications. Since Context7 is a Node.js library consumed by other developers, any security education issues in its documentation can propagate to hundreds or thousands of dependent projects.
The Vulnerability Explained
Let's examine the vulnerable code from docs/api-guide.mdx:
import requests
headers = {"Authorization": "Bearer CONTEXT7_API_KEY"}
# Step 1: Search for the library
search_response = requests.get(
The problem here is subtle but critical. The code uses "Bearer CONTEXT7_API_KEY" as a literal string value in the Authorization header. While experienced developers might recognize this as a placeholder, the pattern creates several risks:
- Copy-paste vulnerability: Developers following the documentation might copy this code directly into their application without modifying the credential handling
- Ambiguous placeholder: The format
CONTEXT7_API_KEYlooks like a valid environment variable name, but it's being used as a string literal rather than being loaded from the environment - No secure pattern demonstration: The example doesn't teach developers the correct way to handle API credentials in Python
How Could This Be Exploited?
Consider this attack scenario specific to Context7 users:
- A developer reads the API guide and copies the example code into their application's
api_client.pyfile - They run the code and it "works" initially because the API endpoint returns a helpful error message about invalid credentials
- The developer assumes they need to "activate" their CONTEXT7_API_KEY somehow, not realizing they need to replace the entire credential-loading pattern
- They commit this code to their repository with the hardcoded placeholder
- An attacker scanning public GitHub repositories searches for the pattern
"Bearer CONTEXT7_API_KEY"and finds dozens of projects using this exact string - The attacker can now identify all applications that followed this documentation pattern and likely have credential management issues
Even worse, if a developer does eventually replace CONTEXT7_API_KEY with their actual API key (like "Bearer sk_live_abc123..."), they've now hardcoded real credentials in their source code—exactly the opposite of secure credential management.
Real-World Impact
For Context7 as a Node.js library, this documentation issue affects every downstream consumer. If 1,000 developers use this library and 10% copy-paste the example code without modification, that's 100 applications potentially exposing API credentials. The vulnerability isn't in Context7's code itself, but in how it teaches developers to use the API—a form of "security education debt" that compounds across the ecosystem.
The Fix
The security fix makes three specific changes to docs/api-guide.mdx:
+import os
import requests
-headers = {"Authorization": "Bearer CONTEXT7_API_KEY"}
+headers = {"Authorization": f"Bearer {os.environ['CONTEXT7_API_KEY']}"}
Let's break down each change:
1. Import the os module
import os
This adds Python's built-in os module, which provides access to environment variables through os.environ.
2. Replace hardcoded string with environment variable lookup
# Before (vulnerable):
headers = {"Authorization": "Bearer CONTEXT7_API_KEY"}
# After (secure):
headers = {"Authorization": f"Bearer {os.environ['CONTEXT7_API_KEY']}"}
The fix uses an f-string (formatted string literal) to dynamically construct the Authorization header by reading the CONTEXT7_API_KEY value from the environment at runtime. This demonstrates the correct pattern: credentials should never be hardcoded as string literals, but should always be loaded from external configuration.
Why This Specific Change Works
The new code provides three security improvements:
- Runtime credential loading: The API key is read from
os.environwhen the code executes, not embedded in the source code - Clear pattern demonstration: Developers copying this example will implement proper environment variable handling by default
- Fail-safe behavior: If the environment variable isn't set, Python raises a
KeyErrorimmediately, preventing the application from running with missing credentials (rather than silently using a placeholder)
The fix also maintains the educational value of the documentation—developers can still follow the complete workflow example, but now they're learning the secure pattern from the start.
Prevention & Best Practices
1. Always Demonstrate Secure Patterns in Documentation
When writing API documentation with code examples, never use bare string literals for credentials, even as placeholders. Instead, show the actual secure implementation:
# ❌ Bad: Looks like a placeholder but teaches wrong pattern
api_key = "YOUR_API_KEY_HERE"
# ✅ Good: Demonstrates proper environment variable usage
api_key = os.environ['API_KEY']
# ✅ Better: Includes error handling
api_key = os.getenv('API_KEY')
if not api_key:
raise ValueError("API_KEY environment variable not set")
2. Use Linters to Catch Documentation Issues
Configure security linters to scan documentation files, not just source code. Tools like Semgrep can detect patterns in Markdown code blocks:
rules:
- id: hardcoded-api-key-in-docs
pattern: |
headers = {"Authorization": "Bearer $KEY"}
message: "Use os.environ['KEY'] instead of hardcoded strings"
languages: [python]
severity: WARNING
3. Provide Complete Setup Instructions
Documentation should include a dedicated "Configuration" section that explains how to set environment variables before showing code examples:
## Configuration
Set your API key as an environment variable:
```bash
export CONTEXT7_API_KEY="your_actual_key_here"
Then use it in your code:
import os
headers = {"Authorization": f"Bearer {os.environ['CONTEXT7_API_KEY']}"}
### 4. Consider Secrets Management for Production
For production applications, document integration with secrets management services:
```python
# Using AWS Secrets Manager
import boto3
import json
def get_api_key():
client = boto3.client('secretsmanager')
response = client.get_secret_value(SecretId='context7/api-key')
return json.loads(response['SecretString'])['api_key']
headers = {"Authorization": f"Bearer {get_api_key()}"}
5. Security Standards Reference
This vulnerability maps to several security standards:
- CWE-798: Use of Hard-coded Credentials
- OWASP Top 10 2021 - A07: Identification and Authentication Failures
- NIST SP 800-53: IA-5 (Authenticator Management)
Key Takeaways
- Documentation code is production code: Examples in
docs/api-guide.mdxare copied directly into applications, so they must demonstrate secure patterns, not just functional patterns - The placeholder
"CONTEXT7_API_KEY"was dangerous: Even though it looks like a placeholder, using it as a string literal teaches developers the wrong credential management pattern - Environment variables are the minimum security bar: The fix using
os.environ['CONTEXT7_API_KEY']demonstrates the baseline secure approach that all Python developers should follow - Library maintainers have ecosystem responsibility: Since Context7 is a Node.js library used by other developers, its documentation security directly impacts hundreds of downstream applications
- Static analysis works on documentation: The multi_agent_ai scanner successfully detected this issue in a Markdown file, proving that security scanning should extend beyond just
.pyor.jsfiles
How Orbis AppSec Detected This
- Source: The hardcoded string literal
"CONTEXT7_API_KEY"in the Python code example withindocs/api-guide.mdx - Sink: The Authorization header construction at line 67, where the placeholder could be copied into production code without modification
- Missing control: No demonstration of environment variable loading or secure credential management in the example code
- CWE: CWE-798 (Use of Hard-coded Credentials)
- Fix: Added
import osand replaced the hardcoded string withos.environ['CONTEXT7_API_KEY']to demonstrate proper environment variable usage
Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.
Conclusion
This vulnerability demonstrates that security issues aren't limited to application code—documentation examples can create just as much risk when they teach insecure patterns. The fix to docs/api-guide.mdx was straightforward: replace the hardcoded "Bearer CONTEXT7_API_KEY" string with proper environment variable loading using os.environ. But the broader lesson is that every code example in documentation should be production-ready and demonstrate security best practices by default.
For developers working on libraries and APIs, remember that your documentation is often the first (and sometimes only) security education your users receive. Make sure every example teaches secure coding from the start, not just functional coding that "works" but creates vulnerabilities downstream.