T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/audit.js:207
- Finding
- SQL Injection Through Unvalidated Probe UID<![CDATA[ ## Vulnerability Details **File Location**: `scripts/audit.js`, lines 207 and 247 **Vulnerability Type**: SQL injection through direct string interpolation **Risk Level**: Critical ### Vulnerable Code ```js await pg.query(`set local request.jwt.claims to '{"sub":"${probeUid}","role":"authenticated"}'`); ``` The same vulnerable statement occurs in both `checkPrivilegeEscalationLive()` and `checkCustomerDataLeak()`. ### Technical Analysis The user-controlled `--probe-uid` argument is inserted directly into a SQL statement. It is neither validated as a UUID nor passed through a query parameter. An attacker can supply a value containing a quote and SQL syntax to terminate the JSON/SQL string and append arbitrary statements. Although the code previously executes `SET LOCAL ROLE authenticated`, the underlying connection authenticates as `postgres.<project-ref>`. Injected SQL could attempt to reset the role or otherwise abuse privileges available to the session. The surrounding transaction and final rollback are not reliable security boundaries. Injected statements could manipulate transaction state, invoke functions with external effects, read protected information, or execute operations whose consequences are not fully neutralized by rollback. ### Attack Path 1. An attacker controls or influences the `--probe-uid` argument supplied to the audit. 2. The malicious value is interpolated into the `SET LOCAL request.jwt.claims` SQL statement. 3. The value terminates the expected string literal and appends attacker-selected SQL. 4. The injected statements execute through the privileged PostgreSQL connection. 5. Depending on database permissions and installed functionality, the attacker may read or modify project data, alter policies or roles, or compromise database integrity. ### Impact Assessment Successful exploitation can provide unauthorized database access within the privileges of the connection. Potential scope includes: - Reading data protect ...[truncated 272 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Validate `probeUid` and `targetUid` against a strict UUID parser before any database operation. 2. Never interpolate claims into SQL. Use a parameterized call to `set_config`: ```js const claims = JSON.stringify({ sub: probeUid, role: 'authenticated', }); await pg.query( `select set_config('request.jwt.claims', $1, true)`, [claims] ); ``` 3. Reject unexpected CLI argument formats and duplicate arguments. 4. Use a dedicated, least-privileged audit database role rather than the database owner or administrative `postgres` identity. 5. Restrict the audit role to the exact schemas, tables, and metadata views required by the checks. 6. Add automated tests using quotes, semicolons, comments, and malformed UUIDs to verify that SQL injection is impossible. ]]>
