T09 · Insecure Skill Coding Practices
- Location
trifle-auth.mjs:39- Finding
Configurable backend permits JWT and SIWE credential disclosure to an arbitrary server
- Content
View full analysis
Vulnerability Details
File Location:
trifle-auth.mjs, lines 39-41 and 96-134
Vulnerability Type: Unrestricted credential destination and cleartext transport permitted
Risk Level: Highjavascript const STATE_FILE = process.env.TRIFLE_AUTH_STATE || join(STATE_DIR, 'auth-state.json'); const SETTINGS_FILE = join(CONFIG_DIR, 'settings.json'); const BACKEND_URL = process.env.TRIFLE_BACKEND_URL || SERVERS.live; async function apiRequest(path, options = {}) { const url = `${BACKEND_URL}${path}`; const res = await fetch(url, { ...options, headers: { 'Content-Type': 'application/json', 'Origin': 'https://trifle.life', 'Referer': 'https://trifle.life/', ...options.headers, }, }); if (!res.ok) { const text = await res.text(); throw new Error(`API error ${res.status}: ${text}`); } return res.json(); } async function authenticatedRequest(path, options = {}) { const state = loadState(); if (!state.token) { throw new Error('Not authenticated. Run: trifle-auth.mjs login'); } return apiRequest(path, { ...options, headers: { 'Authorization': `Bearer ${state.token}`, ...options.headers, }, }); }During login, the same unrestricted request function also transmits the signed SIWE message:
javascript const result = await apiRequest('/auth/wallet/verify', { method: 'POST', body: JSON.stringify({ signature, message, chainId: mainnet.id, }), });Technical Analysis
TRIFLE_BACKEND_URLcompletely controls the origin receiving authentication traffic. The value is not parsed, restricted to an approved hostname, or required to use HTTPS. Consequently, authenticated commands send the stored bearer JWT to any configured destination, including an attacker-controlled server or a cleartext HTTP endpoint.Sending a SIWE signature and JWT to ...[truncated 1743 chars]
- Remediation
View remediation
Remediation Suggestions
- Remove
TRIFLE_BACKEND_URLunless arbitrary backends are a documented and essential feature. - If staging support is required, accept only symbolic values such as
liveandstaging, then map them internally to the hardcoded HTTPS URLs. - Parse the final URL with
new URL()and require:protocol === 'https:'- an exact allowlisted hostname
- no embedded username or password
- an expected port
- Refuse redirects for requests carrying JWTs, or validate every redirect destination before forwarding credentials.
- Maintain separate authentication state per approved server so a staging token cannot be sent to production or vice versa.
- Never attach
Authorizationautomatically to a request until the final destination has passed origin validation. - Add automated tests proving that HTTP URLs, lookalike domains, user-info URL tricks, unexpected ports, and redirects to unapproved hosts are rejected.
- Remove
