T09 · Insecure Skill Coding Practices
- Location
client.js:17- Finding
JWT Stored Without Restrictive File Permissions
- Content
View full analysis
Vulnerability Details
File Location:
client.js, lines 17–22
Vulnerability Type: Insecure local credential storage
Risk Level: MediumVulnerable Code
js function saveJwt(jwt) { const jwtPath = path.join(os.homedir(), '.onhood_jwt'); fs.writeFileSync(jwtPath, jwt, 'utf8'); // Also try to set env for current process process.env.ONHOOD_JWT = jwt; }Technical Analysis
The application stores its JWT bearer token in
~/.onhood_jwtwithout explicitly setting restrictive file permissions. Node.js creates the file using its default mode, generally0666modified by the processumask. If the program runs under a permissiveumask, the resulting file may be readable by other local users. If the file already exists with unsafe permissions, rewriting it does not automatically correct those permissions.Because the JWT is a bearer credential, possession is sufficient to authenticate as the registered onHood agent. No additional secret or proof of identity is applied by the client when issuing authenticated requests.
Attack Path
- A user runs
node client.js register <name>. - The server returns a JWT, and
saveJwt()writes it to~/.onhood_jwt. - The host has a permissive
umask, or the existing token file has overly broad permissions. - Another local user or compromised process reads the JWT file.
- The attacker supplies the stolen value as an
Authorization: Bearer <JWT>header or throughONHOOD_JWT. - The attacker invokes authenticated API operations as the victim's agent.
This attack requires local filesystem access under an identity permitted to read the inadequately protected file.
Impact Assessment
Successful exploitation exposes the victim's onHood authentication token. The attacker could impersonate the victim within the remote service and perform any action authorized by that JWT, including viewing account and world state, sendin ...[truncated 339 chars]
- A user runs
- Remediation
View remediation
Remediation Suggestions
-
Create the JWT file with owner-only permissions:
js fs.writeFileSync(jwtPath, jwt, { encoding: 'utf8', mode: 0o600 }); -
Explicitly enforce permissions after writing so that an existing file with unsafe permissions is corrected:
js fs.chmodSync(jwtPath, 0o600); -
Prevent unsafe handling of pre-existing symbolic links. Use secure exclusive creation where practical, verify the destination with
lstat, and reject symbolic links before replacing or updating the token file. -
Prefer atomic replacement through a securely created owner-only file in the same directory, followed by a rename.
-
Consider using an operating-system credential store or keychain instead of a plaintext file.
-
Document that the token is a sensitive bearer credential and provide a mechanism to revoke or rotate it if disclosure is suspected.
-
