T09 · Insecure Skill Coding Practices
- Location
scripts/main.py:39- Finding
Alumni Personal and Compensation Data Is Stored in Plaintext
- Content
View full analysis
Vulnerability Details
File Location:
scripts/main.py:39-46andscripts/main.py:110-114
Vulnerability Type: Plaintext storage of sensitive personal data
Risk Level: MediumThe application model includes names, employment information, locations, salary ranges, and free-form notes:
python class AlumniRecord: """校友记录数据类""" name: str graduation_year: int degree: str # PhD, Master, Bachelor current_status: str # industry, academia, startup, other organization: str position: str location: str = "" field: str = "" salary_range: str = "" notes: str = ""All fields are serialized directly to an unencrypted JSON file:
python def _save_data(self): """保存数据到文件""" self.data_path.parent.mkdir(parents=True, exist_ok=True) with open(self.data_path, 'w', encoding='utf-8') as f: json.dump([r.to_dict() for r in self.alumni], f, ensure_ascii=False, indent=2)Technical Analysis
AlumniRecord.to_dict()serializes every dataclass field, includingsalary_rangeandnotes._save_data()then writes those values as plaintext JSON. The file is created using the process's ambient umask rather than explicitly restrictive permissions. No encryption, field minimization, access-control validation, consent metadata, or retention mechanism is implemented.The precise exposure depends on deployment permissions. If the resulting file is readable by other local users, shared services, backup operators, or processes running under the same account, those principals can recover the complete stored dataset without needing to bypass application controls.
Attack Path
- An operator adds or imports alumni records containing names, locations, salary ranges, or private notes.
add_alumni()invokes_save_data()._save_data()serializes all record fields intoalumni_data.json, or into the path supplied through `--d ...[truncated 937 chars]
- Remediation
View remediation
Remediation Suggestions
- Minimize collection: do not store salary information or free-form notes unless they are necessary for a documented purpose.
- Separate identifiers from analytical data and use pseudonymous record identifiers where possible.
- Create the data file atomically with owner-only permissions such as
0600; also verify and correct permissions when opening an existing file. - Encrypt sensitive fields or the complete datastore using a managed key that is not stored alongside the data.
- Exclude sensitive fields from default exports and require an explicit, separately authorized option to include them.
- Add consent status, retention deadlines, and deletion support to the data model.
- Aggregate or anonymize records before producing reports, particularly for small cohorts.
- Document backup protections and ensure backups inherit equivalent encryption and access restrictions.
- Add automated tests that verify restrictive permissions and ensure sensitive fields are omitted from anonymized exports.
