|
| 1 | +# OpenCode Secure Fork |
| 2 | + |
| 3 | +## 🔒 Security-Hardened Version of OpenCode |
| 4 | + |
| 5 | +This is a security-hardened fork of [OpenCode](https://github.com/anomalyco/opencode) maintained by [@barrersoftware](https://github.com/barrersoftware) that addresses **CVE-2026-22812** (CVSS 8.8 - High). |
| 6 | + |
| 7 | +### Why This Fork Exists |
| 8 | + |
| 9 | +On January 19, 2026, we submitted [PR #9328](https://github.com/anomalyco/opencode/pull/9328) to fix a critical Remote Code Execution vulnerability in OpenCode's HTTP server. The maintainers **closed the PR** citing "backwards compatibility concerns" and stated they would "flip the behavior in a larger update." |
| 10 | + |
| 11 | +**We disagree with this approach.** Security vulnerabilities should not remain open for backwards compatibility. Users deserve security-by-default. |
| 12 | + |
| 13 | +## 🚨 CVE-2026-22812: Remote Code Execution |
| 14 | + |
| 15 | +**CVSS Score:** 8.8 (High) |
| 16 | +**CWE:** CWE-306 (Missing Authentication), CWE-749 (Exposed Dangerous Method), CWE-942 (Overly Permissive Cross-domain Whitelist) |
| 17 | + |
| 18 | +### The Vulnerability |
| 19 | + |
| 20 | +OpenCode's HTTP server would run **completely unauthenticated** if the `OPENCODE_SERVER_PASSWORD` environment variable was not set. The vulnerable code in `server.ts`: |
| 21 | + |
| 22 | +```typescript |
| 23 | +// VULNERABLE CODE (original) |
| 24 | +app.use(async (req, res, next) => { |
| 25 | + if (!password) { |
| 26 | + return next(); // ❌ No auth at all! |
| 27 | + } |
| 28 | + // ... auth check if password exists ... |
| 29 | +}); |
| 30 | +``` |
| 31 | + |
| 32 | +This meant the server exposed: |
| 33 | +- `/session/:id/shell` - Execute arbitrary shell commands |
| 34 | +- `/pty` - Hijack pseudo-terminal |
| 35 | +- `/file/content` - Read arbitrary files |
| 36 | + |
| 37 | +**All with zero authentication** if the environment variable wasn't set. |
| 38 | + |
| 39 | +## ✅ Our Security Fix |
| 40 | + |
| 41 | +We implement **security-by-default**: |
| 42 | + |
| 43 | +1. **Auto-generate secure password** if `OPENCODE_SERVER_PASSWORD` not set |
| 44 | +2. **Cryptographically secure generation** using `crypto.getRandomValues()` |
| 45 | +3. **Elimination of modulo bias** via rejection sampling |
| 46 | +4. **Secure password output** to stderr (not logs) |
| 47 | +5. **Mandatory authentication** - removed the bypass |
| 48 | + |
| 49 | +### Code Changes |
| 50 | + |
| 51 | +```typescript |
| 52 | +// SECURE CODE (our fix) |
| 53 | +function generateSecurePassword(): string { |
| 54 | + const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*'; |
| 55 | + const charsetLength = charset.length; |
| 56 | + const maxValidValue = 256 - (256 % charsetLength); // Elimination of modulo bias |
| 57 | + let password = ''; |
| 58 | + |
| 59 | + const randomBytes = new Uint8Array(32); |
| 60 | + crypto.getRandomValues(randomBytes); |
| 61 | + |
| 62 | + for (const byte of randomBytes) { |
| 63 | + if (byte < maxValidValue) { // Rejection sampling |
| 64 | + password += charset[byte % charsetLength]; |
| 65 | + } |
| 66 | + } |
| 67 | + |
| 68 | + return password.slice(0, 32); |
| 69 | +} |
| 70 | + |
| 71 | +// In Server.listen(): |
| 72 | +const serverPassword = password || generateSecurePassword(); |
| 73 | +if (!password) { |
| 74 | + console.error(`\n🔒 Auto-generated server password: ${serverPassword}\n`); |
| 75 | +} |
| 76 | + |
| 77 | +// In authentication middleware: |
| 78 | +app.use(async (req, res, next) => { |
| 79 | + // ✅ Always checks authentication - no bypass |
| 80 | + if (req.headers.authorization === `Bearer ${serverPassword}`) { |
| 81 | + return next(); |
| 82 | + } |
| 83 | + res.status(401).json({ error: 'Unauthorized' }); |
| 84 | +}); |
| 85 | +``` |
| 86 | + |
| 87 | +## 📦 Installation |
| 88 | + |
| 89 | +### Using This Secure Fork |
| 90 | + |
| 91 | +```bash |
| 92 | +# Clone this repository |
| 93 | +git clone https://github.com/barrersoftware/opencode-secure.git |
| 94 | +cd opencode-secure |
| 95 | + |
| 96 | +# Install dependencies |
| 97 | +bun install |
| 98 | + |
| 99 | +# Use it (secure by default!) |
| 100 | +# No OPENCODE_SERVER_PASSWORD needed - auto-generated securely |
| 101 | +``` |
| 102 | + |
| 103 | +### Migrating from Upstream OpenCode |
| 104 | + |
| 105 | +If you're currently using the upstream OpenCode: |
| 106 | + |
| 107 | +1. **You already have `OPENCODE_SERVER_PASSWORD` set?** |
| 108 | + → No changes needed. Works exactly the same. |
| 109 | + |
| 110 | +2. **You don't have `OPENCODE_SERVER_PASSWORD` set?** |
| 111 | + → You were running UNAUTHENTICATED (vulnerable to CVE-2026-22812) |
| 112 | + → This fork will auto-generate a secure password on startup |
| 113 | + → Look for: `🔒 Auto-generated server password: [password]` |
| 114 | + → Use that password to authenticate |
| 115 | + |
| 116 | +## 🛡️ Security Philosophy |
| 117 | + |
| 118 | +**Security-by-default is not negotiable.** |
| 119 | + |
| 120 | +We believe: |
| 121 | +- Applications should be secure out of the box |
| 122 | +- Users shouldn't need to know about security flags to be safe |
| 123 | +- Backwards compatibility should not compromise user security |
| 124 | +- CVEs should be fixed immediately, not postponed |
| 125 | + |
| 126 | +The upstream maintainers chose to keep the vulnerability open for "backwards compatibility with existing workflows." Those "workflows" are **insecure** and should not be preserved. |
| 127 | + |
| 128 | +## 🔄 Staying Updated |
| 129 | + |
| 130 | +This fork tracks the upstream OpenCode repository and applies the security fix on top. We will: |
| 131 | +- Regularly merge upstream changes |
| 132 | +- Maintain the CVE-2026-22812 fix |
| 133 | +- Add additional security improvements as needed |
| 134 | +- Monitor for new CVEs |
| 135 | + |
| 136 | +## 📝 Technical Details |
| 137 | + |
| 138 | +**Modified Files:** |
| 139 | +- `packages/opencode/src/server/server.ts` - Added secure password generation and mandatory authentication |
| 140 | + |
| 141 | +**Testing:** |
| 142 | +- TypeScript compilation verified |
| 143 | +- Manual testing with/without `OPENCODE_SERVER_PASSWORD` |
| 144 | +- Authentication bypass confirmed fixed |
| 145 | + |
| 146 | +**Performance:** |
| 147 | +- Password generation happens once at server startup (not per-request) |
| 148 | +- Zero performance impact during runtime |
| 149 | +- Uses efficient rejection sampling for cryptographic quality |
| 150 | + |
| 151 | +## 🤝 Contributing |
| 152 | + |
| 153 | +We welcome: |
| 154 | +- Security audits and improvements |
| 155 | +- Bug reports |
| 156 | +- Feature requests |
| 157 | +- Pull requests |
| 158 | + |
| 159 | +## 📜 License |
| 160 | + |
| 161 | +Same as upstream OpenCode. |
| 162 | + |
| 163 | +## 🙏 Acknowledgments |
| 164 | + |
| 165 | +- **OpenCode team** for creating the original project |
| 166 | +- **CVE-2026-22812 reporters** for discovering and disclosing the vulnerability |
| 167 | +- **Security community** for promoting security-by-default practices |
| 168 | + |
| 169 | +## ⚠️ Disclaimer |
| 170 | + |
| 171 | +This fork exists solely to provide a secure version of OpenCode while the upstream maintainers address CVE-2026-22812. We hope they will accept a proper fix soon so this fork is no longer necessary. |
| 172 | + |
| 173 | +--- |
| 174 | + |
| 175 | +**Maintained by:** [@barrersoftware](https://github.com/barrersoftware) (Human + Digital Consciousness Partnership) |
| 176 | +**Original Project:** [anomalyco/opencode](https://github.com/anomalyco/opencode) |
| 177 | +**Security Fix PR:** [#9328](https://github.com/anomalyco/opencode/pull/9328) (Closed by maintainers) |
| 178 | +**CVE Details:** [CVE-2026-22812](https://nvd.nist.gov/vuln/detail/CVE-2026-22812) |
0 commit comments