T09 · Insecure Skill Coding Practices
- Location
scripts/noise_log.py:28- Finding
Sensitive records are written without restrictive permissions or symlink protections
- Content
View full analysis
Vulnerability Details
File Locations:
scripts/noise_log.py:28-29scripts/noise_log.py:199-205scripts/noise_log.py:303-306
Vulnerability Type: Insecure file creation, plaintext sensitive-data exposure, and symlink-following overwrite
Risk Level: MediumVulnerable Code
scripts/noise_log.py:28-29:python def save(db, path): json.dump(db, open(path, "w"), indent=2)scripts/noise_log.py:199-205:python fields = ["start", "weekday", "hour", "duration_min", "type", "loudness", "impact", "neighbor", "note"] with open(a.csv, "w", newline="") as f: w = csv.DictWriter(f, fieldnames=fields) w.writeheader() for i in incs: w.writerow({k: i.get(k, "") for k in fields})scripts/noise_log.py:303-306:python out = os.path.join(os.path.dirname(a.file) or ".", f"noise-complaint-{a.to}.txt") with open(out, "w") as f: f.write(body) print(f"\n[saved to {out} — review and edit before sending]", file=sys.stderr)Technical Analysis
The application stores noise-incident records, CSV exports, and generated complaint letters as plaintext files using ordinary
open(..., "w")calls. It does not explicitly apply owner-only permissions such as0600; therefore, the resulting permissions depend on the processumask. Under a permissive configuration, other local users may be able to read these files.The records may include names, residential addresses, phone numbers, neighbor or unit identifiers, household impacts, incident notes, and allegations about responsible parties. This makes the files privacy-sensitive even though no credentials are stored.
The write operations also follow symbolic links and silently truncate existing files. The complaint-letter filename is predictable, such as
noise-complaint-landlord.txt. If the selected directory is shared or attacker-controlled, a local attacker can pre-create that file ...[truncated 1848 chars]- Remediation
View remediation
Remediation Suggestions
-
Create private data files atomically with owner-only permissions:
- Use
os.open()withos.O_WRONLY | os.O_CREAT | os.O_TRUNCand mode0o600. - For new destinations that must not exist, add
os.O_EXCL. - Wrap the descriptor with
os.fdopen()and always use a context manager.
- Use
-
Prevent symbolic-link attacks:
- Add
os.O_NOFOLLOWwhere supported. - Inspect destinations with
os.lstat()and reject symbolic links. - Do not perform a separate check followed by an ordinary
open(), because that introduces a time-of-check/time-of-use race. - Prefer atomic creation in a trusted, user-owned directory.
- Add
-
Avoid silent overwrites:
- Require an explicit overwrite option for existing exports and letters.
- Otherwise, use exclusive creation or generate a unique filename.
- If replacement is required, write to a private temporary file in the same directory and atomically replace the destination after validation.
-
Harden existing storage:
- Apply
os.chmod(path, 0o600)to existing user data files after verifying that the path is a regular file and not a symbolic link. - Verify that the parent directory is owned by the expected user and is not writable by untrusted accounts.
- Apply
-
Improve resource handling:
- Replace
json.load(open(path))andjson.dump(..., open(path, "w"))with explicitwithblocks to guarantee prompt file closure and reliable error handling.
- Replace
-
Document that JSON logs, CSV exports, and complaint letters contain sensitive personal and allegation data, and advise users not to place them in shared directories.
-
