Back to skill

Security audit

food-recall-radar

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent pantry recall checker with local storage and openFDA lookup; the main caution is avoiding verbose mode with an API key because it can print the key.

Before installing, understand that your pantry inventory and recall-hit history are saved locally by default at ~/.pantry.json. Live checks contact openFDA, but pantry contents are matched locally. If you use an openFDA API key, avoid --verbose until the script redacts the key; rotate the key if you previously ran keyed verbose checks in logs others can access.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/recall_radar.py:95
Finding
Optional openFDA API Key Exposed Through Verbose Logging<![CDATA[ ## Vulnerability Details **File Location**: `scripts/recall_radar.py:95-101` **Vulnerability Type**: Sensitive credential exposure through diagnostic output **Risk Level**: Medium ### Vulnerable Code ```python def fetch_recalls(api_key=None, limit=1000, verbose=False): q = urllib.parse.quote('status:"Ongoing"') url = f"{OPENFDA}?search={q}&limit={limit}" if api_key: url += f"&api_key={api_key}" if verbose: print(f"# fetching {url}", file=sys.stderr) ``` ### Technical Analysis The optional openFDA API key is appended directly to the request URL. When the user enables `--verbose`, the complete URL—including the unredacted API key—is written to standard error. Standard error may be retained by CI/CD systems, shell-session recorders, scheduled-job logs, monitoring platforms, container logs, or shared terminal capture systems. Anyone able to read those records could recover the credential. The live network request itself is consistent with the Skill's declared purpose: it contacts the documented openFDA HTTPS endpoint to retrieve ongoing recall records. Pantry brands, products, UPCs, lots, and notes are not added to the request. The vulnerability is therefore the unnecessary disclosure of the API key in diagnostic output, not unauthorized transmission of pantry information. ### Attack Path 1. A user supplies an openFDA key through `--api-key` or the `OPENFDA_API_KEY` environment variable. 2. The user runs the `match` or `audit` command with `--verbose`. 3. `get_recalls()` passes the key to `fetch_recalls()`. 4. `fetch_recalls()` appends the key to the URL as the `api_key` query parameter. 5. Verbose mode prints the complete URL to standard error. 6. A local user, log reader, CI operator, monitoring-system user, or other party with access to retained output extracts the API key. 7. The party reuses the key to make requests attributed to the victim and consume the associated openFDA quota. ### Impact Assessment Succe ...[truncated 511 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Never print a URL containing the real API key. Redact the value before logging: ```python if verbose: safe_url = url if api_key: safe_url = safe_url.replace( f"api_key={urllib.parse.quote(str(api_key))}", "api_key=[REDACTED]", ) print(f"# fetching {safe_url}", file=sys.stderr) ``` 2. Prefer constructing query parameters with `urllib.parse.urlencode()` instead of manual string concatenation, and generate a separate sanitized representation for diagnostics. 3. If supported by openFDA, transmit credentials through an authorization header rather than a query parameter. Query parameters are more likely to appear in proxy, access, and diagnostic logs. 4. Keep verbose output limited to non-sensitive information, such as the hostname, endpoint path, recall status, and result limit: ```python if verbose: print( f"# fetching {OPENFDA} " f"(status=Ongoing, limit={limit}, api_key={'set' if api_key else 'unset'})", file=sys.stderr, ) ``` 5. Add an automated test that invokes verbose mode with a sentinel API key and asserts that the sentinel never appears in stdout or stderr. 6. Users who previously ran keyed requests with `--verbose` should inspect relevant logs and rotate the openFDA key if those logs were accessible to untrusted parties. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Missing User Warnings

Low
Confidence
84% confidence
Finding
This code stores pantry contents by default in ~/.pantry.json, and later commands persist item details and recall-hit history to that file. Although file storage is part of the tool's purpose, there is no user-facing warning that household purchase/inventory data will be retained locally.

External Transmission

Medium
Category
Data Exfiltration
Content
from difflib import SequenceMatcher

DEFAULT_PANTRY = os.path.join(os.path.expanduser("~"), ".pantry.json")
OPENFDA = "https://api.openfda.gov/food/enforcement.json"

# ---------------------------------------------------------------- normalize
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
if a.verbose:
            print(f"# using cached data: {a.data}", file=sys.stderr)
        return load_cached(a.data)
    api_key = a.api_key or os.environ.get("OPENFDA_API_KEY")
    try:
        return fetch_recalls(api_key=api_key, verbose=a.verbose)
    except Exception as e:
Confidence
70% confidence
Finding
Code accesses environment variables that may contain secrets (API keys, tokens). This is a common pattern for credential theft.

Scope Creep

Low
Category
Excessive Agency
Content
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Confidence
70% confidence
Finding
Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Static analysis

No suspicious patterns detected.