- Location
- scripts/onboarding.js:43
- Finding
- Privileged API Credentials Are Stored in Plaintext Configuration<![CDATA[
## Vulnerability Details
**File Location**: `scripts/onboarding.js:43-74`
**Additional Locations**: `SKILL.md:339-369`, `references/revenuecat-integration.md:5-16`
**Vulnerability Type**: Plaintext credential storage
**Risk Level**: High
### Vulnerable Code
```javascript
const configTemplate = {
app: {
name: '',
description: '',
audience: '',
problem: '',
differentiator: '',
appStoreUrl: '',
category: '',
isMobileApp: false
},
imageGen: {
provider: '',
apiKey: '',
model: ''
},
postiz: {
apiKey: '',
integrationIds: {
tiktok: ''
}
},
revenuecat: {
enabled: false,
v2SecretKey: '',
projectId: ''
},
posting: {
privacyLevel: 'SELF_ONLY',
schedule: ['07:30', '16:30', '21:00'],
crossPost: []
},
competitors: `${dir}/competitor-research.json`,
strategy: `${dir}/strategy.json`
};
const cfgPath = `${dir}/config.json`;
if (!fs.existsSync(cfgPath)) {
fs.writeFileSync(cfgPath, JSON.stringify(configTemplate, null, 2));
console.log(`📝 Created ${cfgPath}`);
}
```
The Skill documentation instructs users to populate these fields directly:
```json
{
"imageGen": {
"provider": "openai",
"apiKey": "sk-...",
"model": "gpt-image-1.5"
},
"postiz": {
"apiKey": "your-postiz-key"
},
"revenuecat": {
"enabled": false,
"v2SecretKey": "sk_...",
"projectId": "proj..."
}
}
```
### Technical Analysis
The generated `config.json` is designed to contain OpenAI, Stability AI, or Replicate credentials, a Postiz API key, and a privileged RevenueCat secret key. The file is written using default filesystem permissions and without encryption, an operating-system secret store, environment-variable indirection, or an explicit restrictive mode such as `0600`.
The project also does not create or verify a `.gitignore` rule for the generated marketing directory. Consequently, credentials may be included in source-control commits, backups,
...[truncated 1696 chars]
- Remediation
- <![CDATA[
## Remediation Suggestions
1. Remove secret values from `config.json`. Store only environment-variable names or secret references, for example:
```json
{
"imageGen": {
"apiKeyEnv": "OPENAI_API_KEY"
},
"postiz": {
"apiKeyEnv": "POSTIZ_API_KEY"
},
"revenuecat": {
"apiKeyEnv": "RC_API_KEY"
}
}
```
2. Update every script to resolve credentials from `process.env` or an operating-system secret manager.
3. If a local secret file must be supported:
- Create it with mode `0600`.
- Keep it separate from non-secret configuration.
- Refuse to run if permissions permit group or world access.
4. Automatically add generated secret files and the relevant local workspace to `.gitignore`.
5. Add validation that detects credentials committed to configuration and warns the user without printing the secret.
6. Request provider keys with the narrowest available scopes and separate read-only analytics keys from posting or administrative keys.
7. Document rotation and revocation procedures.
8. Make the RevenueCat instructions consistent with the executable implementation by using `RC_API_KEY` throughout.
]]>