T09 · Insecure Skill Coding Practices
- Location
scripts/bookstack.py:14- Finding
BookStack API Credentials May Be Transmitted over an Untrusted Transport
- Content
View full analysis
Vulnerability Details
File Location:
scripts/bookstack.py, lines 14-41
Vulnerability Type: Missing HTTPS enforcement for authenticated API requests
Risk Level: MediumVulnerable Code
python # Configuration from environment BASE_URL = os.getenv('BOOKSTACK_URL', '').rstrip('/') TOKEN_ID = os.getenv('BOOKSTACK_TOKEN_ID', '') TOKEN_SECRET = os.getenv('BOOKSTACK_TOKEN_SECRET', '') def api_call(method, endpoint, data=None, params=None): """Make API call to BookStack""" if not BASE_URL or not TOKEN_ID or not TOKEN_SECRET: print("❌ Error: BOOKSTACK_URL, BOOKSTACK_TOKEN_ID, and BOOKSTACK_TOKEN_SECRET required!") print(" Set them as environment variables or in your gateway config.") sys.exit(1) url = f"{BASE_URL}/api/{endpoint}" if params: url += '?' + urllib.parse.urlencode(params) try: req = urllib.request.Request( url, headers={ "Authorization": f"Token {TOKEN_ID}:{TOKEN_SECRET}", "Content-Type": "application/json", "Accept": "application/json" }, method=method ) if data: data = {k: v for k, v in data.items() if v is not None} req.data = json.dumps(data).encode() with urllib.request.urlopen(req, timeout=30) as response:Technical Analysis
The script accepts
BOOKSTACK_URLdirectly from the environment and does not parse its scheme or require HTTPS. It subsequently places the long-lived BookStack token ID and secret in theAuthorizationheader of every API request.If
BOOKSTACK_URLuses plain HTTP, neither the credentials nor the request and response content receive transport-layer confidentiality or integrity protection. An attacker able to observe or alter network traffic could capture the token, modify API operations, or tamper with returned content.The standard URL-opening behavior also ...[truncated 1882 chars]
- Remediation
View remediation
Remediation Suggestions
- Parse
BOOKSTACK_URLwithurllib.parse.urlparse()before making any request. - Require the
httpsscheme by default and reject HTTP, unsupported schemes, missing hostnames, fragments, and embedded user information. - If local development requires HTTP, permit it only through an explicit opt-in setting and restrict it to loopback hosts such as
localhost,127.0.0.1, or::1. - Disable redirects for authenticated requests or implement a redirect handler that allows only same-origin HTTPS redirects. Reject HTTPS-to-HTTP downgrades and changes to the scheme, hostname, or effective port.
- Use a least-privilege BookStack API token dedicated to this integration.
- Rotate the token immediately if it may previously have been used over HTTP or sent to an untrusted endpoint.
- Document HTTPS as mandatory rather than presenting it only as an example configuration.
Example validation logic:
python parsed = urllib.parse.urlparse(BASE_URL) if ( parsed.scheme != "https" or not parsed.hostname or parsed.username is not None or parsed.password is not None or parsed.fragment ): raise ValueError( "BOOKSTACK_URL must be a valid HTTPS URL without embedded credentials" )Redirect restrictions must additionally be implemented in the HTTP client because initial URL validation alone does not constrain subsequent redirect destinations.
- Parse
