T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/ontology.py:28
- Finding
- Missing Schema Enforcement Allows Plaintext Credential Storage and Invalid Graph Records<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ontology.py:28-40`, `scripts/ontology.py:143-156`, and `scripts/ontology.py:243-245` **Vulnerability Type**: Missing input validation and plaintext sensitive-data storage **Risk Level**: Medium ### Vulnerable Code Entity properties are persisted without schema or credential-safety validation: ```python def create_entity(entity_type, properties): ensure_dirs() entity_id = generate_id(entity_type) entity = { "id": entity_id, "type": entity_type, "properties": properties, "created": datetime.utcnow().isoformat() + "Z", "updated": datetime.utcnow().isoformat() + "Z" } record = {"op": "create", "entity": entity} with open(GRAPH_FILE, 'a') as f: f.write(json.dumps(record) + "\n") return entity ``` The CLI accepts arbitrary JSON properties and passes them directly to the storage function: ```python if cmd == "create": entity_type, props = None, {} i = 2 while i < len(sys.argv): if sys.argv[i] == "--type" and i + 1 < len(sys.argv): entity_type = sys.argv[i + 1]; i += 2 elif sys.argv[i] == "--props" and i + 1 < len(sys.argv): props = json.loads(sys.argv[i + 1]); i += 2 else: i += 1 if not entity_type: print("Error: --type is required"); sys.exit(1) result = create_entity(entity_type, props) ``` The validation command does not inspect any stored data or load the declared schema: ```python elif cmd == "validate": ensure_dirs() print("✅ Validation passed") ``` This conflicts with the declared credential rules in `references/schema.md:125-131`: ```yaml Credential: required: [service, secret_ref] forbidden_properties: [password, secret, token, key, api_key] properties: service: string secret_ref: string # Reference to secret store (e.g., "keychain:github-token") expires: datetime? scope: string[]? ``` ### Technical Analysis Th ...[truncated 3476 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Load an authoritative machine-readable schema before accepting any write. The existing Markdown reference should be converted into or backed by a real schema file. 2. Allow only explicitly defined entity types and properties. Reject unknown types rather than assigning them a generic identifier prefix. 3. Validate all required properties, data types, enum values, date formats, URLs, and reference values before persistence. 4. For `Credential` entities, reject direct secret-bearing fields such as `password`, `secret`, `token`, `key`, and `api_key`, including an agreed case-normalization policy. 5. Require `secret_ref` to point to an approved secret-management mechanism. Never persist the corresponding secret value in the graph. 6. Validate relations before writing them: - Confirm that both endpoint entities exist. - Enforce allowed source and destination types. - Enforce cardinality rules. - Reject unsupported relation names. - Perform graph traversal to prevent cycles in relations marked as acyclic. 7. Replace the unconditional `validate` response with a complete scan of stored entities and relations. Print actionable validation errors and return a nonzero status when any violation is found. 8. Create the storage directory and graph file with least-privilege permissions, such as directory mode `0700` and file mode `0600`, without relying solely on the process umask. 9. Add tests proving that forbidden credential fields, missing required fields, invalid enums, nonexistent relation endpoints, and dependency cycles are rejected. 10. Review existing `graph.jsonl` records for secrets. Remove exposed values safely and rotate any credentials that may already have been persisted. ]]>
