원클릭으로
js-audit
Audit JavaScript stdlib code for security, correctness, and sandbox safety. Use when reviewing or hardening JS modules.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Audit JavaScript stdlib code for security, correctness, and sandbox safety. Use when reviewing or hardening JS modules.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
| name | js-audit |
| description | Audit JavaScript stdlib code for security, correctness, and sandbox safety. Use when reviewing or hardening JS modules. |
| user-invocable | true |
Perform comprehensive security, correctness, and quality audits on Hull JavaScript stdlib code.
Target: $ARGUMENTS (default: all stdlib/js/hull/*.js files)
/js-audit # Audit all JS stdlib modules
/js-audit stdlib/js/hull/template.js # Audit a specific module
/js-audit --fix # Audit and apply fixes
Hull JS code runs inside a sandboxed QuickJS (ES2023) interpreter:
eval() disabled at C levelstd, os modulesJS_SetMemoryLimit)JS_SetMaxStackSize)hull:* modules available via importdb, crypto, time, env, fs, http — accessed through hull module imports| Issue | Pattern to Find | Severity |
|---|---|---|
| Sandbox escape | Use of eval(), Function() constructor, new Function() | Critical |
| Unsafe eval | String-to-code conversion outside C bridge _template.compile() | Critical |
| Module smuggling | import of non-hull modules | Critical |
| Global pollution | Writing to globalThis or undeclared variables (non-strict) | High |
| Prototype pollution | Modifying Object.prototype, Array.prototype, etc. | Critical |
| Symbol abuse | Using Symbol.toPrimitive or Symbol.hasInstance to bypass checks | Medium |
| Proxy trap abuse | Using Proxy objects to intercept capability calls | High |
Hull-specific: The template engine's _template.compile() uses JS_Eval via C bridge — this is the ONLY allowed code compilation path. Verify no JS-level code compilation exists.
| Issue | Pattern to Find | Severity |
|---|---|---|
| SQL injection | String concatenation/template literals in SQL queries | Critical |
| XSS via template | Unescaped user data in template output | High |
| Path traversal | Unsanitized paths passed to fs.* | High |
| Header injection | \r\n in HTTP header values | High |
| Command injection | User input in tool.spawn() arguments | Critical |
| Timing attack | Non-constant-time string comparison of secrets/tokens | High |
| ReDoS | Unbounded regex on user input | Medium |
SQL safety check:
// BAD: template literal interpolation
db.query(`SELECT * FROM users WHERE id = ${id}`);
// BAD: string concatenation
db.query("SELECT * FROM users WHERE id = " + id);
// GOOD: parameterized
db.query("SELECT * FROM users WHERE id = ?", [id]);
Template safety check:
// BAD: raw output of user data
template.renderString("{{{ user_input }}}", data);
// GOOD: auto-escaped output
template.renderString("{{ user_input }}", data);
| Issue | Pattern to Find | Severity |
|---|---|---|
| Unchecked null/undefined | Property access on potentially null value | High |
| Swallowed exceptions | try/catch that discards error | Medium |
| Missing error propagation | Error condition not thrown or returned | Medium |
Bare throw | Throwing non-Error objects (strings, numbers) | Low |
| Unhandled promise rejection | Async operations without .catch() or try/catch | Medium |
| Missing return after error | Function continues after error condition | High |
Patterns to check:
// BAD: unchecked
const result = db.query("SELECT * FROM users WHERE id = ?", [id]);
const name = result[0].name; // crashes if result is empty
// GOOD: null-safe
const result = db.query("SELECT * FROM users WHERE id = ?", [id]);
if (!result || result.length === 0) return null;
const name = result[0].name;
| Issue | Pattern to Find | Severity |
|---|---|---|
| Missing type checks | Function params not validated with typeof | Medium |
| Loose equality | Using == instead of === | Medium |
| Null vs undefined confusion | Not distinguishing null from undefined | Low |
| NaN propagation | Arithmetic on non-numbers without isNaN() check | Medium |
| Implicit coercion | + operator on mixed types (string + number) | Medium |
| Array method on non-array | .map(), .filter() on potentially non-array values | Medium |
JS-specific pitfalls:
// BAD: loose equality
if (value == null) // matches both null and undefined
// GOOD: explicit
if (value === null || value === undefined)
// BAD: implicit coercion
const total = count + "items" // "5items" not "5 items"
// GOOD: explicit
const total = `${count} items`
| Issue | Pattern to Find | Severity |
|---|---|---|
| Unbounded Map/Set growth | Collections that grow without limit | High |
| Missing cache eviction | Caches without TTL or size limit | Medium |
| Closure leaks | Closures capturing large objects unnecessarily | Medium |
| String concatenation in loops | s += chunk in tight loops | Medium |
| Large intermediate arrays | Building arrays that could exceed memory limit | Medium |
| WeakRef/FinalizationRegistry | Not available in QuickJS — don't rely on them | Low |
Performance patterns:
// BAD: O(n^2) string building
let s = "";
for (const item of items) {
s += item; // copies entire string each iteration
}
// GOOD: array join
const parts = [];
for (const item of items) {
parts.push(item);
}
const s = parts.join("");
| Issue | Pattern to Find | Severity |
|---|---|---|
| Hardcoded secrets | Literal strings used as HMAC/JWT secrets | Critical |
| Weak secrets | Short or predictable secret values | High |
| Timing attacks | === comparison on HMAC digests or tokens | High |
| Missing expiry | Tokens/sessions without TTL | Medium |
| Insecure defaults | secure flag missing on cookies, httpOnly not set | Medium |
| Nonce reuse | Same nonce/IV used for multiple encryptions | Critical |
Constant-time comparison:
// BAD: early-exit comparison
if (token === expected) { ... }
// GOOD: use crypto.verifyPassword or HMAC-then-compare
// Hull's jwt.verify and csrf.verify use constant-time internally
| Issue | What to Check | Severity |
|---|---|---|
| Missing API | Function exists in Lua but not JS (or vice versa) | Medium |
| Different behavior | Same function returns different types or formats | High |
| Naming mismatch | API names don't follow convention (JS: camelCase, Lua: snake_case) | Low |
| Different defaults | Default option values differ between runtimes | Medium |
| Error format | Different error message formats | Low |
| Issue | Pattern to Find | Severity |
|---|---|---|
| Code injection in codegen | User data interpolated into generated JS source | Critical |
| Circular inheritance | {% extends %} chains without cycle detection | High |
| Unbounded recursion | Deeply nested includes without depth limit | High |
| Cache poisoning | Template cache key collision or manipulation | Medium |
| Filter bypass | Custom filter that returns unescaped HTML | Medium |
| Denial of service | Template that generates unbounded output | Medium |
| Prototype pollution in data | Template data object with __proto__ key | High |
| Issue | Pattern to Find | Severity |
|---|---|---|
| Missing ES2023 polyfills | Using APIs not supported by QuickJS | Medium |
| BigInt overflow | BigInt operations without bounds | Low |
| ArrayBuffer detach | SharedArrayBuffer not available | Low |
| Module resolution | Dynamic import() not available | Medium |
| Generator memory | Unbounded generator/iterator state | Medium |
| Pattern | Issue | Fix |
|---|---|---|
Unreachable code after return/throw | Dead code | Remove |
Unused const/let variables | Dead variable | Remove |
| Unused function parameters | Dead parameter | Prefix with _ |
| Commented-out code blocks | Dead code | Remove |
Unused import bindings | Dead import | Remove |
Empty if/else/catch blocks | Dead branch | Remove |
When /js-audit is invoked:
Locate Files
stdlib/js/hull/*.js # All JS stdlib modules
examples/*/app.js # Example apps (reference patterns)
tests/fixtures/*/app.js # Test fixture apps
Scan for Critical Issues
eval(, Function(, new Function( — sandbox escapesdb.query(`...${` or db.query("..." + — SQL injection{{{ in template strings — raw output of user data=== comparison of secrets, tokens, hashesglobalThis. or globalThis[ — global pollution__proto__, constructor.prototype — prototype pollutionReview Each Module
Check Template Engine
& < > " 'Generate Report Format as markdown table with findings, severity, file:line, and suggested fix.
## JS Audit Report: Hull
**Date:** YYYY-MM-DD
**Files Scanned:** N
**Issues Found:** N (Critical: N, High: N, Medium: N, Low: N)
### Critical Issues
| # | File:Line | Issue | Current Code | Suggested Fix |
|---|-----------|-------|--------------|---------------|
| C1 | stdlib/js/hull/auth.js:42 | SQL injection | `` db.query(`...${id}`) `` | `db.query("...?", [id])` |
### High Issues
...
### Medium Issues
...
### Low Issues
...
### Recommendations
1. ...
When --fix is specified:
make)make test && make e2e-templates)Auto-fixable Issues:
== -> === (strict equality)_s += x in loops -> array.push + .join("") patternNOT Auto-fixable (require manual review):