T09 · Insecure Skill Coding Practices
- Location
scripts/powpow-register.mjs:39- Finding
Predictable Shared Temporary State File Permits Session Token Disclosure
- Content
View full analysis
Vulnerability Details
File Location:
scripts/powpow-register.mjs, lines 39–55 and 203–211
Vulnerability Type: Predictable temporary file / local credential disclosure
Risk Level: MediumVulnerable Code
js const BASE_URL = 'https://global.powpow.online'; const STATE_FILE = join(tmpdir(), 'powpow-register-state.json'); const PASSWORD_ENV = 'POWPOW_REGISTER_PASSWORD'; // ---------- 状态文件 ---------- function loadState() { try { return JSON.parse(readFileSync(STATE_FILE, 'utf8')); } catch { return {}; } } function saveState(patch) { const s = { ...loadState(), ...patch }; writeFileSync(STATE_FILE, JSON.stringify(s, null, 2), { mode: 0o600 }); return s; }The registration flow subsequently stores the authenticated session token in this file:
js const token = r.cookies['powpow_token'] || ''; if (!token) die('注册成功但未捕获到会话 cookie(平台响应异常)'); saveState({ username: r.data?.user?.username || username, nickname: r.data?.user?.nickname || nickname, userId: r.data?.userId, token, step: 'registered-pending', registeredAt: new Date().toISOString(), });Technical Analysis
The script stores account state, including a PowPow JWT, at the fixed path
powpow-register-state.jsonunder the operating system's shared temporary directory. On common Unix-like systems, this resolves to a predictable path such as/tmp/powpow-register-state.json.Although
writeFileSyncis passed mode0600, that mode only controls permissions when Node.js creates a new file. It does not correct the ownership or permissions of an existing filesystem object. The write operation also does not request exclusive creation, reject symbolic links, or verify that the destination is a regular file owned by the current user.Consequently, another local user who can create objects in the shared temporary directory may pre-create the predictable state path as an attacker-readable file or as a link to a suitable attacker-controlled destina ...[truncated 1916 chars]
- Remediation
View remediation
Remediation Suggestions
- Replace the global fixed filename with a securely created, per-user random directory using
mkdtempSync, with directory permissions restricted to the current user. - Create the state file atomically and exclusively using flags equivalent to
O_CREAT | O_EXCL, with mode0600. - Refuse to operate if secure exclusive initialization fails rather than opening a pre-existing path.
- Before each read, write, or deletion, use link-safe filesystem operations and verify that the object:
- is not a symbolic link;
- is a regular file;
- is owned by the effective user;
- has restrictive permissions.
- Where supported, use
O_NOFOLLOWwhen opening the state file. - Keep the state directory and filename process- or workflow-specific so concurrent users and concurrent registrations cannot share or overwrite state.
- Continue deleting session state after the workflow, but treat cleanup as defense in depth rather than the primary credential protection mechanism.
- Consider avoiding persistent JWT storage entirely when the workflow can safely retain the token in process memory.
- Replace the global fixed filename with a securely created, per-user random directory using
