Skip to content

Commit 89d69cd

Browse files
alsk1992claude
andcommitted
Security audit and fixes before npm publish
## Fixes Applied - Updated nodemailer to 7.0.13 (fixes DoS and email interpretation vulnerabilities) - Fixed command injection in src/nodes/index.ts (execSync -> execFileSync) - Fixed command injection in src/macos/index.ts (execSync -> execFileAsync with arrays) - Added security warning to unsafe sandbox in src/security/index.ts ## Documentation - Added SECURITY.md with vulnerability reporting policy - Added docs/SECURITY_AUDIT.md with full audit report ## Remaining (upstream dependencies) - 34 vulnerabilities in transitive dependencies (axios, bigint-buffer, elliptic, undici) - These require breaking changes to upstream packages (Solana, Cosmos, Discord) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 5b1cb92 commit 89d69cd

7 files changed

Lines changed: 365 additions & 25 deletions

File tree

SECURITY.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Security Policy
2+
3+
## Supported Versions
4+
5+
| Version | Supported |
6+
| ------- | ------------------ |
7+
| 0.1.x | :white_check_mark: |
8+
9+
## Reporting a Vulnerability
10+
11+
**Please do NOT report security vulnerabilities through public GitHub issues.**
12+
13+
Instead, please report them via one of these methods:
14+
15+
1. **GitHub Security Advisories** (Preferred)
16+
- Go to the [Security tab](https://github.com/alsk1992/CloddsBot/security/advisories)
17+
- Click "Report a vulnerability"
18+
- Fill out the form with details
19+
20+
2. **Email**
21+
- Send details to the repository owner
22+
- Include "SECURITY" in the subject line
23+
24+
### What to Include
25+
26+
- Type of issue (e.g., command injection, credential exposure, etc.)
27+
- Full paths of source file(s) related to the issue
28+
- Location of the affected source code (tag/branch/commit or direct URL)
29+
- Step-by-step instructions to reproduce the issue
30+
- Proof-of-concept or exploit code (if possible)
31+
- Impact of the issue
32+
33+
### Response Timeline
34+
35+
- **Initial response:** Within 48 hours
36+
- **Status update:** Within 7 days
37+
- **Fix timeline:** Depends on severity
38+
- Critical: 24-72 hours
39+
- High: 1-2 weeks
40+
- Medium: 2-4 weeks
41+
- Low: Next release
42+
43+
## Security Best Practices for Users
44+
45+
### Credential Safety
46+
47+
1. **Never commit credentials** - Use environment variables
48+
2. **Use `.env` files** - Keep them in `.gitignore`
49+
3. **Rotate API keys** - Regularly rotate trading platform keys
50+
4. **Limit permissions** - Use read-only keys when possible
51+
52+
### Deployment
53+
54+
1. **Keep dependencies updated** - Run `npm audit` regularly
55+
2. **Use HTTPS** - Never expose HTTP endpoints publicly
56+
3. **Enable rate limiting** - Protect against abuse
57+
4. **Review logs** - Monitor for suspicious activity
58+
59+
### Trading Safety
60+
61+
1. **Start with dry-run mode** - Test before live trading
62+
2. **Set loss limits** - Configure circuit breakers
63+
3. **Use separate wallets** - Don't use primary wallets for bots
64+
4. **Monitor positions** - Set up alerts for large trades
65+
66+
## Known Security Considerations
67+
68+
### npm Dependencies
69+
70+
Some transitive dependencies have known vulnerabilities that cannot be fixed without breaking changes:
71+
72+
- `@solana/spl-token` chain (bigint-buffer)
73+
- `@cosmjs/*` chain (elliptic)
74+
- `@orca-so/whirlpool-sdk` (axios)
75+
76+
These are monitored and will be updated when upstream fixes are available.
77+
78+
### Sandbox Limitations
79+
80+
The `createSandbox()` function in `src/security/index.ts` is NOT a secure sandbox. It should only be used for trusted code. For untrusted code execution, use Docker containers or `isolated-vm`.
81+
82+
## Security Audit
83+
84+
See [docs/SECURITY_AUDIT.md](./docs/SECURITY_AUDIT.md) for the full security audit report.

docs/SECURITY_AUDIT.md

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
# Security Audit Report
2+
3+
**Date:** 2026-01-30
4+
**Version:** 0.1.0
5+
**Status:** Pre-release audit
6+
7+
---
8+
9+
## Executive Summary
10+
11+
| Category | Critical | High | Medium | Low | Total |
12+
|----------|----------|------|--------|-----|-------|
13+
| npm Dependencies | 0 | 16 | 6 | 13 | 35 |
14+
| Code Vulnerabilities | 0 | 2 | 4 | 3 | 9 |
15+
| **Total** | **0** | **18** | **10** | **16** | **44** |
16+
17+
**Recommendation:** Fix HIGH severity issues before npm publish.
18+
19+
---
20+
21+
## 1. npm Dependency Vulnerabilities (35)
22+
23+
### HIGH Severity (16)
24+
25+
#### 1.1 axios ≤0.29.0 (GHSA-wf5p-g6vw-rhxx, GHSA-jr5f-v2jv-69x6)
26+
- **Issue:** CSRF vulnerability, SSRF and credential leakage via absolute URL
27+
- **Affected:** `@orca-so/whirlpool-sdk`
28+
- **Fix:** Update whirlpool-sdk or replace with alternative
29+
- **Priority:** HIGH
30+
31+
#### 1.2 bigint-buffer (GHSA-3gc7-fjrx-p6mg)
32+
- **Issue:** Buffer overflow via toBigIntLE()
33+
- **Affected:** `@solana/buffer-layout-utils`, `@solana/spl-token`, `@solana/web3.js`
34+
- **Fix:** `npm audit fix --force` (breaking change to wormhole-sdk)
35+
- **Priority:** HIGH
36+
37+
#### 1.3 elliptic (GHSA-848j-6mx2-7j84)
38+
- **Issue:** Cryptographic primitive with risky implementation
39+
- **Affected:** `@cosmjs/crypto`, `secp256k1`
40+
- **Fix:** Update secp256k1 to 1.1.6+ (breaking change)
41+
- **Priority:** HIGH - affects crypto signing
42+
43+
### MODERATE Severity (6)
44+
45+
#### 1.4 nanoid <3.3.8 (GHSA-mwcw-c2x4-8c55)
46+
- **Issue:** Predictable results with non-integer values
47+
- **Affected:** `@drift-labs/sdk`
48+
- **Fix:** Update drift-labs/sdk
49+
- **Priority:** MEDIUM
50+
51+
#### 1.5 nodemailer ≤7.0.10 (GHSA-mm7p-fcc7-pg87, GHSA-rcmh-qjqh-p98v)
52+
- **Issue:** Email domain interpretation conflict, DoS via recursion
53+
- **Affected:** Direct dependency
54+
- **Fix:** `npm update nodemailer` to 7.0.13+
55+
- **Priority:** MEDIUM
56+
57+
#### 1.6 undici <6.23.0 (GHSA-g9mf-h72j-4rw9)
58+
- **Issue:** Unbounded decompression chain DoS
59+
- **Affected:** `discord.js`, `@discordjs/rest`
60+
- **Fix:** Update discord.js
61+
- **Priority:** MEDIUM
62+
63+
### LOW Severity (13)
64+
- Various transitive dependencies with minor issues
65+
- Most are informational or require specific conditions to exploit
66+
67+
---
68+
69+
## 2. Code Vulnerabilities
70+
71+
### HIGH Risk
72+
73+
#### 2.1 Command Injection - `src/nodes/index.ts`
74+
```typescript
75+
// VULNERABLE: User-controlled paths in shell commands
76+
execSync(`ffmpeg ... -y "${outPath}" ...`);
77+
execSync(`say "${text.replace(/"/g, '\\"')}"`);
78+
execSync(`notify-send "${title}" "${body}"`);
79+
```
80+
- **Risk:** If `outPath`, `text`, `title`, or `body` contain shell metacharacters, arbitrary commands can be executed
81+
- **Fix:** Use `execFile()` with array arguments instead of `execSync()` with string interpolation
82+
- **Files:** `src/nodes/index.ts`, `src/macos/index.ts`
83+
84+
#### 2.2 Unsafe Sandbox - `src/security/index.ts`
85+
```typescript
86+
// WARNING in code: "Very basic sandboxing - in production, use vm2 or isolated-vm"
87+
const fn = new Function(...Object.keys(sandbox), `"use strict"; return (${code})`);
88+
```
89+
- **Risk:** `new Function()` can be escaped; sandbox is not secure
90+
- **Fix:** Replace with `isolated-vm` or `vm2` for production use
91+
- **Files:** `src/security/index.ts:558`
92+
93+
### MEDIUM Risk
94+
95+
#### 2.3 Prototype Pollution Risk
96+
```typescript
97+
Object.assign(opp, scored); // If 'scored' has __proto__, pollution possible
98+
```
99+
- **Risk:** If external data is merged without sanitization
100+
- **Files:** Multiple files use `Object.assign()` with external data
101+
- **Fix:** Validate objects before merging, use `Object.create(null)` for maps
102+
103+
#### 2.4 Credential Logging Risk
104+
- **Risk:** 388 `process.env` references - ensure sensitive vars aren't logged
105+
- **Fix:** Audit all logging calls to ensure no credential exposure
106+
- **Files:** Throughout codebase
107+
108+
#### 2.5 Path Traversal - Potential
109+
- **Risk:** User-controlled paths could escape intended directories
110+
- **Fix:** Validate and normalize paths, use `path.resolve()` with base checks
111+
- **Files:** File operation handlers
112+
113+
#### 2.6 Missing Rate Limiting
114+
- **Risk:** API endpoints without rate limiting could be abused
115+
- **Fix:** Implement rate limiting on all public endpoints
116+
- **Files:** `src/gateway/`
117+
118+
### LOW Risk
119+
120+
#### 2.7 Error Message Information Disclosure
121+
- **Risk:** Detailed error messages may leak internal paths/state
122+
- **Fix:** Sanitize error messages in production
123+
124+
#### 2.8 Insecure Randomness
125+
- **Risk:** `Math.random()` used in some non-crypto contexts
126+
- **Fix:** Use `crypto.randomBytes()` for any security-sensitive randomness
127+
128+
#### 2.9 Missing Input Validation
129+
- **Risk:** Some API inputs not fully validated
130+
- **Fix:** Add input validation schemas (zod/joi)
131+
132+
---
133+
134+
## 3. Remediation Plan
135+
136+
### Phase 1: Critical Fixes (Before npm Publish)
137+
138+
| # | Issue | Fix | Status |
139+
|---|-------|-----|--------|
140+
| 1 | nodemailer | Updated to 7.0.13 | ✅ DONE |
141+
| 2 | Command injection | Replaced execSync with execFileSync in nodes/index.ts and macos/index.ts | ✅ DONE |
142+
| 3 | Unsafe sandbox | Added security warning + production logging in security/index.ts | ✅ DONE |
143+
144+
### Phase 2: High Priority (Next Release)
145+
146+
| # | Issue | Fix | Effort |
147+
|---|-------|-----|--------|
148+
| 4 | elliptic/secp256k1 | Update with breaking change testing | 4 hours |
149+
| 5 | bigint-buffer | Update Solana libs | 4 hours |
150+
| 6 | axios in orca-sdk | Replace orca-sdk or patch | 2 hours |
151+
| 7 | discord.js undici | Update discord.js | 1 hour |
152+
153+
### Phase 3: Hardening (Ongoing)
154+
155+
| # | Issue | Fix | Effort |
156+
|---|-------|-----|--------|
157+
| 8 | Prototype pollution | Add object sanitization | 2 hours |
158+
| 9 | Rate limiting | Add express-rate-limit | 2 hours |
159+
| 10 | Input validation | Add zod schemas | 4 hours |
160+
| 11 | Credential audit | Review all logging | 2 hours |
161+
162+
---
163+
164+
## 4. Security Best Practices Implemented
165+
166+
**Encrypted credentials** - AES-256-GCM at rest
167+
**No hardcoded secrets** - All from environment
168+
**HTTPS enforced** - For all API calls
169+
**Webhook signature verification** - HMAC validation
170+
**SQL injection prevention** - Parameterized queries
171+
**Audit logging** - All trades logged
172+
173+
---
174+
175+
## 5. Recommended Security Headers
176+
177+
Add to gateway responses:
178+
```typescript
179+
{
180+
'X-Content-Type-Options': 'nosniff',
181+
'X-Frame-Options': 'DENY',
182+
'X-XSS-Protection': '1; mode=block',
183+
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
184+
'Content-Security-Policy': "default-src 'self'",
185+
}
186+
```
187+
188+
---
189+
190+
## 6. Before Publishing Checklist
191+
192+
- [ ] Fix nodemailer vulnerability
193+
- [ ] Fix command injection in nodes/index.ts
194+
- [ ] Add sandbox warning or replace with vm2
195+
- [ ] Run `npm audit` - ensure no critical/high in direct deps
196+
- [ ] Test all trading functions work after updates
197+
- [ ] Review this document with team
198+
199+
---
200+
201+
## 7. Disclosure Policy
202+
203+
Security issues should be reported to: security@clodds.dev (or GitHub Security Advisories)
204+
205+
Do NOT create public issues for security vulnerabilities.
206+
207+
---
208+
209+
*Generated by security audit on 2026-01-30*

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"url": "https://github.com/alsk1992/CloddsBot/issues"
4545
},
4646
"engines": {
47-
"node": ">=20"
47+
"node": ">=20.0.0"
4848
},
4949
"license": "MIT",
5050
"repository": {
@@ -90,7 +90,7 @@
9090
"inquirer": "^9.2.14",
9191
"json5": "^2.2.3",
9292
"node-cron": "^3.0.3",
93-
"nodemailer": "^6.10.1",
93+
"nodemailer": "^7.0.13",
9494
"pg": "^8.17.2",
9595
"pino": "^8.18.0",
9696
"pino-pretty": "^10.3.1",
@@ -113,8 +113,5 @@
113113
"puppeteer": "^24.36.1",
114114
"tsx": "^4.7.0",
115115
"typescript": "^5.3.3"
116-
},
117-
"engines": {
118-
"node": ">=20.0.0"
119116
}
120117
}

src/macos/index.ts

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -632,23 +632,34 @@ function escapeString(str: string): string {
632632

633633
/** Open URL in default browser */
634634
export async function openUrl(url: string): Promise<void> {
635+
// Validate URL to prevent command injection
636+
if (!url.startsWith('http://') && !url.startsWith('https://') && !url.startsWith('file://')) {
637+
throw new Error('Invalid URL: must start with http://, https://, or file://');
638+
}
639+
640+
const { execFile } = require('child_process');
641+
const execFileAsync = promisify(execFile);
642+
635643
if (isMacOS()) {
636-
await execAsync(`open "${url}"`);
644+
await execFileAsync('open', [url]);
645+
} else if (platform() === 'win32') {
646+
await execFileAsync('cmd', ['/c', 'start', '', url]);
637647
} else {
638-
const { execSync } = require('child_process');
639-
const cmd = platform() === 'win32' ? 'start' : 'xdg-open';
640-
execSync(`${cmd} "${url}"`);
648+
await execFileAsync('xdg-open', [url]);
641649
}
642650
}
643651

644652
/** Open file with default application */
645-
export async function openFile(path: string, app?: string): Promise<void> {
653+
export async function openFile(filePath: string, app?: string): Promise<void> {
646654
assertMacOS();
647655

656+
const { execFile } = require('child_process');
657+
const execFileAsync = promisify(execFile);
658+
648659
if (app) {
649-
await execAsync(`open -a "${app}" "${path}"`);
660+
await execFileAsync('open', ['-a', app, filePath]);
650661
} else {
651-
await execAsync(`open "${path}"`);
662+
await execFileAsync('open', [filePath]);
652663
}
653664
}
654665

0 commit comments

Comments
 (0)