T09 · Insecure Skill Coding Practices
- Location
scripts/lib/storage.py:14- Finding
Sensitive Insurance Records Stored with Implicit Filesystem Permissions
- Content
View full analysis
Vulnerability Details
File Location:
scripts/lib/storage.py:14-15, 31, 35-36, 42-44
Vulnerability Type: Plaintext sensitive-data storage with insufficiently enforced access controls
Risk Level: MediumThe storage implementation creates the insurance directory and writes JSON records without explicitly enforcing owner-only permissions:
python def ensure_dir() -> None: os.makedirs(INSURANCE_DIR, exist_ok=True)python with open(filepath, "r", encoding="utf-8") as f: return json.load(f)python corrupt_backup = f"{filepath}.corrupt.{timestamp}.bak" shutil.copy(filepath, corrupt_backup)python def save_json(filename: str, data: dict) -> None: ensure_dir() filepath = _path(filename) with open(filepath, "w", encoding="utf-8") as f: json.dump(data, f, indent=2, ensure_ascii=False)The affected files can contain policy numbers, insured names, premiums, coverage limits, deductibles, notes, claim descriptions, claim statuses, and incident dates, as populated by
scripts/add_policy.py:64-78andscripts/log_claim.py:34-42.Technical Analysis
The records are stored as unencrypted JSON. Directory and file permissions depend on the process umask and pre-existing workspace permissions rather than being explicitly restricted to the owning user. Reopening an existing file with
open(..., "w")does not correct an already permissive mode.When malformed JSON is detected,
shutil.copycreates another plaintext copy. This expands the sensitive-data footprint and provides no explicit retention or secure-deletion control. The write operation is also non-atomic, meaning interruption can leave a partially written file and trigger creation of further backup copies on a later read.This issue is relevant when the workspace is shared, the process runs with a permissive umask, existing files have broad permissions, or another local process executes under an identity able to access the workspace.
A
...[truncated 1298 chars]
- Remediation
View remediation
Remediation Suggestions
-
Create the insurance directory with owner-only permissions and repair permissions when it already exists:
python os.makedirs(INSURANCE_DIR, mode=0o700, exist_ok=True) os.chmod(INSURANCE_DIR, 0o700) -
Create files with mode
0600, avoiding reliance on the process umask. Useos.openwith explicit flags and permissions, then wrap the descriptor withos.fdopen. -
Replace direct truncating writes with atomic persistence:
- Securely create a temporary file inside
INSURANCE_DIR. - Set its mode to
0600. - Write and flush the JSON.
- Call
os.fsync. - Atomically replace the destination with
os.replace. - Clean up the temporary file on failure.
- Securely create a temporary file inside
-
Explicitly set corruption-backup files to mode
0600. Define a retention limit and provide a user-controlled deletion mechanism so stale sensitive copies do not accumulate indefinitely. -
Check that
WORKSPACE_ROOTandINSURANCE_DIRare not symlinks or unexpectedly owned/writable by other users before storing records. -
Consider encryption at rest with a user-managed key when the threat model includes other privileged local processes, backups, or offline disk access. Filesystem permissions alone do not protect against administrators or compromise of the owning account.
-
Add tests that run under permissive umasks and verify that the directory remains
0700and all records, backups, and temporary files remain0600.
-
