T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/transfer.sh:50
- Finding
- Unsafe JSON Construction in Authenticated Financial Transactions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/transfer.sh:50-63`; `scripts/ynab-helper.sh:77-92` **Vulnerability Type**: Unescaped input interpolation into JSON request bodies **Risk Level**: High ### Vulnerable Code From `scripts/transfer.sh:50-63`: ```bash RESPONSE=$(curl -s -X POST "$YNAB_API/budgets/$BUDGET_ID/transactions" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d "{ \"transaction\": { \"account_id\": \"$SOURCE_ACCOUNT_ID\", \"date\": \"$DATE\", \"amount\": $AMOUNT_MILLIUNITS, \"payee_id\": \"$TRANSFER_PAYEE_ID\", \"memo\": \"$MEMO\", \"approved\": true } }") ``` A second instance exists in `scripts/ynab-helper.sh:77-92`: ```bash curl -X POST "$YNAB_API/budgets/$BUDGET_ID/transactions" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d "{ \"transaction\": { \"account_id\": \"$ACCOUNT_ID\", \"date\": \"$DATE\", \"amount\": $AMOUNT_MILLI, \"payee_name\": \"$PAYEE\", \"category_id\": \"$CATEGORY_ID\", \"memo\": \"$MEMO\", \"approved\": true } }" | jq . ``` ### Technical Analysis Both scripts construct JSON by directly inserting shell variables into a double-quoted string. Values such as `MEMO`, `PAYEE`, `ACCOUNT_ID`, `CATEGORY_ID`, and `DATE` are not JSON-escaped. A value containing a quotation mark, backslash, newline, or JSON syntax can terminate the intended string and add or alter properties in the request body. At minimum, ordinary input containing these characters produces malformed JSON and prevents the transaction from being created. A deliberately crafted value may modify request semantics, depending on how YNAB handles duplicate JSON properties. The affected requests use a valid bearer token and invoke a financial write endpoint, making robust serialization essential. ### Attack Path 1. An attacker or untrusted user supplies a crafted memo, payee ...[truncated 1095 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Construct request bodies with a JSON serializer rather than string interpolation. For example: ```bash PAYLOAD=$(jq -n \ --arg account_id "$SOURCE_ACCOUNT_ID" \ --arg date "$DATE" \ --arg payee_id "$TRANSFER_PAYEE_ID" \ --arg memo "$MEMO" \ --argjson amount "$AMOUNT_MILLIUNITS" \ '{ transaction: { account_id: $account_id, date: $date, amount: $amount, payee_id: $payee_id, memo: $memo, approved: true } }') RESPONSE=$(curl --fail-with-body --silent --show-error \ -X POST "$YNAB_API/budgets/$BUDGET_ID/transactions" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ --data-binary "$PAYLOAD") ``` Apply the same pattern to `ynab-helper.sh`. Additional hardening should include: 1. Validate account, category, and payee identifiers against expected UUID formats or API-derived identifiers. 2. Validate dates using a strict `YYYY-MM-DD` pattern and calendar round-trip check. 3. Validate amounts before passing them as `--argjson`. 4. Reject control characters where they are not required. 5. Display the fully normalized transaction and request explicit confirmation before a financial write. 6. Check the HTTP status and response schema before reporting success. ]]>
