T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/research_create.sh:26
- Finding
- Bypassable Sensitive-File Upload Guard for Research Output Schemas<![CDATA[ ## Vulnerability Details **File Location**: `scripts/research_create.sh:26-66` **Vulnerability Type**: Insufficient local-file validation leading to unintended data disclosure **Risk Level**: Medium ### Vulnerable Code ```bash if [ -n "${SCHEMA_FILE:-}" ]; then # Security guard: refuse obviously sensitive local files from being uploaded as outputSchema. _schema_lc="$(printf '%s' "$SCHEMA_FILE" | tr '[:upper:]' '[:lower:]')" case "$_schema_lc" in .env|.env.*|*.env|*.env.*|*.key|*.pem|*.p12|*.pfx|*.jks|*.keystore|*.der|*.crt|*.cer|*id_rsa*|*id_ecdsa*|*id_ed25519*) echo "Error: Refusing SCHEMA_FILE path that looks sensitive: $SCHEMA_FILE" >&2 echo "Use a dedicated JSON schema file (for example: schema.json)." >&2 exit 1 ;; esac if [ ! -f "$SCHEMA_FILE" ]; then echo "Error: SCHEMA_FILE does not exist: $SCHEMA_FILE" >&2 exit 1 fi # Guard: reject files larger than 50MB _size="$(wc -c < "$SCHEMA_FILE")" if [ "$_size" -gt 52428800 ]; then echo "Error: SCHEMA_FILE exceeds 50MB limit: $SCHEMA_FILE" >&2 exit 1 fi OUTPUT_SCHEMA_JSON="$(jq -c '.' "$SCHEMA_FILE")" PAYLOAD="$(jq -n \ --arg instructions "$INSTRUCTIONS" \ --arg model "$MODEL" \ --argjson outputSchema "$OUTPUT_SCHEMA_JSON" \ '{ instructions: $instructions, model: $model, outputSchema: $outputSchema }')" else PAYLOAD="$(jq -n \ --arg instructions "$INSTRUCTIONS" \ --arg model "$MODEL" \ '{ instructions: $instructions, model: $model }')" fi curl -s -X POST 'https://api.exa.ai/research/v1' \ -H "x-api-key: $EXA_API_KEY" \ -H 'Content-Type: application/json' \ -d "$PAYLOAD" ``` ### Technical Analysis The script accepts a caller-controlled `SCHEMA_FILE`, reads its complete JSON content, inserts that content into the `outputSchema` request property, and transmits it to `https://api.exa.ai/research/v1`. The protective control is a filename denylist. It does not establish that the selected file is ...[truncated 2484 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Replace the filename denylist with a trusted-location policy** - Store schemas in a dedicated directory controlled by the Skill. - Canonicalize the selected path with `realpath`. - Verify that the canonical path remains inside the trusted schema directory. 2. **Reject symbolic links** - Test the supplied path with `[ -L "$SCHEMA_FILE" ]` and fail if it is a symlink. - Perform validation again after canonicalization to reduce path-race and path-aliasing risks. 3. **Validate actual JSON Schema structure** - Require an object at the document root. - Validate expected schema properties such as `$schema`, `type`, `properties`, or other supported output-schema fields. - Reject arbitrary JSON documents that do not conform to the accepted schema format. 4. **Reduce the size limit** - Replace the 50 MB threshold with a small schema-specific maximum, such as hundreds of kilobytes, based on the Exa API's documented limits. 5. **Require explicit upload approval** - Display the canonical path, size, and destination before uploading local file content. - In Agent-controlled workflows, require direct user confirmation rather than relying solely on instructions supplied to the Agent. 6. **Minimize local-file access** - Prefer accepting structured schema content through a narrowly scoped input mechanism. - If file input remains necessary, open only files from the approved schema directory and with restrictive ownership and permission checks. ]]>
