T09 · Insecure Skill Coding Practices
- Location
scripts/easycode_skill.py:1044- Finding
Plaintext Database Password Persisted and Exposed Through State Output
- Content
View full analysis
Vulnerability Details
File Location:
scripts/easycode_skill.py:1044-1050,scripts/easycode_skill.py:1055-1069, andscripts/easycode_skill.py:1151-1153
Vulnerability Type: Plaintext credential storage and disclosure
Risk Level: HighVulnerable Code
python return { "db_connection": { "db_type": db_type, "url": url, "user": user, "pass": passw, "driver_jar": driver_jar, "driver_class": driver_class, }, "generation_config": gen, }python def cmd_state(args: argparse.Namespace) -> int: state = _load_state() if args.show: print(json.dumps(state, ensure_ascii=False, indent=2)) return 0 if args.save: if not args.spec: raise SystemExit("--save requires --spec") spec = _parse_spec(args.spec) merged = merge_with_state(spec, state) merged["updated_at"] = _now_iso() _save_state(merged) print(str(STATE_FILE)) return 0python merged["updated_at"] = _now_iso() _save_state(merged)The underlying state writer stores the supplied object without removing sensitive fields:
python def _save_state(state: dict) -> None: STATE_DIR.mkdir(parents=True, exist_ok=True) with STATE_FILE.open("w", encoding="utf-8") as f: json.dump(state, f, ensure_ascii=False, indent=2)Technical Analysis
Interactive configuration places the database password in
db_connection.pass. Both the explicitstate --saveoperation and a successful interactive run pass the complete merged configuration to_save_state. No redaction, encryption, secret-manager integration, or restrictive file mode is applied.The resulting
.easycode-skill/state.jsontherefore contains the password in plaintext. Thestate --showcommand subsequently prints the entire state object, including that passw ...[truncated 1609 chars]- Remediation
View remediation
Remediation Suggestions
- Remove
passbefore every call to_save_state:python persisted = copy.deepcopy(merged) persisted.get("db_connection", {}).pop("pass", None) _save_state(persisted) - Request the password for each metadata-fetch operation or accept it through a protected secret input channel.
- If reuse is required, persist only a secret-manager reference and resolve it at runtime.
- Redact sensitive fields in
state --show, including passwords and any future tokens. - Create the state directory with restrictive permissions and write the state file with mode
0600. - Add automated tests confirming that serialized state and command output never contain
pass. - Document
.easycode-skill/in recommended ignore rules to reduce accidental commits.
- Remove
