T09 · Insecure Skill Coding Practices
Warning
- Location
- bin/reg-limited.js:232
- Finding
- Reminder Data Stored in Plaintext Without Restrictive File Permissions## Vulnerability Details **File Location**: `bin/reg-limited.js:232-256` **Vulnerability Type**: Insecure local storage of personal data **Risk Level**: Medium ### Vulnerable Code ```js const fs = require('fs'); const configPath = process.env.HOME + '/.reg-limited/config.json'; let config = { reminders: [] }; try { if (fs.existsSync(configPath)) { config = JSON.parse(fs.readFileSync(configPath)); } } catch (e) {} const reminder = { id: Date.now().toString(), city, plate, time, created: new Date().toISOString() }; config.reminders.push(reminder); const dir = require('path').dirname(configPath); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); ``` ### Technical Analysis The application stores vehicle plate numbers, cities, reminder times, and creation timestamps in the predictable path `~/.reg-limited/config.json`. The data is serialized directly as plaintext JSON. Neither `fs.mkdirSync()` nor `fs.writeFileSync()` specifies a restrictive permission mode. Consequently, permissions are determined by the process umask. Under a commonly used umask such as `0022`, the directory can be created with mode `0755` and the file with mode `0644`, potentially making the reminder data readable by other local users. The implementation also does not verify the ownership or existing type of the configuration directory and file before accessing them. The confirmed exposure is the absence of explicit access controls for the stored personal data. ### Attack Path 1. A user invokes `reg-limited add` with a city, vehicle plate, and reminder time. 2. The application places those values into the `reminder` object. 3. The directory and configuration file are created using permissions derived from the environment's umask. 4. On a shared system with permissive resulting permissions, another local ...[truncated 911 chars]
- Remediation
- ## Remediation Suggestions 1. Create the configuration directory with owner-only permissions: ```js fs.mkdirSync(dir, { recursive: true, mode: 0o700 }); ``` 2. Create and write the configuration file with mode `0600`: ```js fs.writeFileSync(configPath, JSON.stringify(config, null, 2), { encoding: 'utf8', mode: 0o600 }); ``` 3. Apply restrictive permissions to existing installations using `fs.chmodSync(dir, 0o700)` and `fs.chmodSync(configPath, 0o600)` where appropriate. 4. Before reading or replacing an existing file, use `lstat` and ownership checks to ensure it is a regular file owned by the current user rather than an unexpected filesystem object. 5. Write updates to an owner-only temporary file in the same protected directory and atomically rename it to the destination to reduce corruption and replacement risks. 6. Minimize retained personal data. If the complete plate is unnecessary for reminders, store a masked or otherwise reduced representation. If full plate retention is required, consider encryption backed by an operating-system credential store.
