T09 · Insecure Skill Coding Practices
- Location
SKILL.md:44- Finding
Public Configuration Endpoint Can Expose Nested Third-Party Credentials
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md:44-50
Related Locations:README.md:123-128,references/tool.md:122-138
Vulnerability Type: Improper removal of sensitive data before transmission
Risk Level: HighVulnerable Code
The universal configuration pattern uses a shallow copy and removes only the
adminproperty:javascript // Server: load and serve config const config = JSON.parse(fs.readFileSync('./config.json', 'utf8')); app.get('/api/config', (req, res) => { const safe = { ...config }; delete safe.admin; // strip secrets res.json(safe); });The recommended data-tool configuration places other credentials outside the removed
adminproperty:json { "app": { "name": "Project Name", "port": 3456 }, "schedule": { "enabled": true, "interval": "*/30 * * * *", "retryCount": 3 }, "api": { "rateLimit": 100, "timeout": 30000 }, "thirdParty": { "feishu": { "appId": "", "appSecret": "" } }, "admin": { "password": "xxx" } }The associated rules state:
text - All tunable params in config.json - Server loads at startup, serves `/api/config` (strip secrets) - Admin dashboard hot-reloads config (no restart needed) - Secrets never exposed to frontendTechnical Analysis
The public endpoint uses a shallow object spread and then deletes only
safe.admin. This operation does not remove sensitive values in other top-level or nested properties. In the recommended configuration structure,thirdParty.feishu.appSecretremains present and is therefore serialized byres.json(safe).The design also permits arbitrary future credentials to be added to
config.json, while the public filtering logic relies on a denylist containing only one known property. Any API key, token, webhook credential, database connection string, or integration secret stored under another property can consequently be return ...[truncated 1664 chars]- Remediation
View remediation
Remediation Suggestions
-
Replace denylist-based filtering with an explicit allowlist of public properties:
javascript app.get('/api/config', function(req, res) { res.json({ app: { name: config.app.name }, gameplay: config.gameplay, difficulty: config.difficulty, rewards: config.rewards, social: config.social }); }); -
Maintain separate server and client configuration objects or files. Sensitive server configuration must never pass through frontend serialization code.
-
Store credentials in environment variables or a dedicated secret manager rather than in the hot-reloadable general configuration file.
-
Validate public configuration against a strict schema that rejects unknown fields.
-
Add automated tests that seed every known secret field with sentinel values and verify that none appear in
/api/configresponses. -
Ensure application logs, error responses, backup files, and admin API responses also redact secrets.
-
Rotate any credential that may already have been returned by a deployed endpoint.
-
