T09 · Insecure Skill Coding Practices
- Location
scripts/helper.py:151- Finding
Plaintext Disclosure of Zotero API Credentials Through Diagnostic Output
- Content
View full analysis
Vulnerability Details
File Location:
scripts/helper.py, lines 15–22 and 151–154
Vulnerability Type: Sensitive credential exposure through plaintext logging
Risk Level: MediumVulnerable Code
python DEFAULT_CONFIG = { "zotero_api_key": os.environ.get("ZOTERO_API_KEY", ""), "zotero_user_id": os.environ.get("ZOTERO_USER_ID", ""), "zotero_collection_key": os.environ.get("ZOTERO_COLLECTION_KEY", "U4PZ3XNP"), "obsidian_vault_path": os.environ.get("OBSIDIAN_VAULT_PATH", ""), "obsidian_folder": os.environ.get("OBSIDIAN_FOLDER", "DailyArXiv"), "arxiv_base_url": "https://arxiv.drqyq.com", "category": "PTA", }python if __name__ == "__main__": print("Arxiv-Zotero-Obsidian Helper Script") print("=" * 40) print(f"Default config: {json.dumps(DEFAULT_CONFIG, indent=2)}")Technical Analysis
DEFAULT_CONFIGstores the live value of theZOTERO_API_KEYenvironment variable alongside the Zotero user ID and local Obsidian vault path. When the helper is executed directly, the entire dictionary is serialized to JSON and printed without redaction.Although reading the API key is necessary for the declared Zotero synchronization function, disclosing it through standard output is not necessary and exceeds minimum information exposure. Standard output may be retained in CI/CD logs, agent transcripts, terminal recordings, monitoring platforms, scheduled-task logs, or diagnostic reports.
The audit found that normal API use sends the key in the
Zotero-API-Keyheader exclusively over HTTPS to the officialapi.zotero.orgendpoint. No evidence was found that the key, vault contents, notes, or environment data are transmitted to an unrelated network destination. The vulnerability is therefore the local plaintext output of the credential rather than unauthorized network exfiltration.Attack Path
- A user configures `ZOTERO_A ...[truncated 1380 chars]
- Remediation
View remediation
Remediation Suggestions
- Remove the complete configuration dump from the
__main__block. - If diagnostic output is required, construct an explicit allowlist of non-sensitive fields rather than serializing the full configuration object.
- Always replace the API key with a fixed marker such as
[REDACTED]; do not reveal prefixes, suffixes, or key length. - Avoid printing local vault paths, user identifiers, and collection keys unless they are essential for a specific diagnostic operation.
- Use a logging framework with centralized secret-redaction controls and ensure production logging does not run at a level that exposes configuration details.
- Revoke and rotate any Zotero API key that may already have appeared in logs or transcripts.
- Review and delete retained logs containing the exposed configuration where operationally possible.
- Configure the Zotero key with only the permissions needed to create the intended items and attachments, and use a dedicated key for this Skill when possible.
A safe diagnostic pattern would be:
python if __name__ == "__main__": safe_config = { "zotero_api_key": "[REDACTED]" if DEFAULT_CONFIG["zotero_api_key"] else "", "category": DEFAULT_CONFIG["category"], "obsidian_folder": DEFAULT_CONFIG["obsidian_folder"], "arxiv_base_url": DEFAULT_CONFIG["arxiv_base_url"], } print("Arxiv-Zotero-Obsidian Helper Script") print("=" * 40) print(f"Configuration: {json.dumps(safe_config, indent=2)}")- Remove the complete configuration dump from the
