[Question For Security Improvement] Hardcoded JWT secret `MY_SECRET` permits forged authentication cookies
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 62/100
- Tipo di issue
- Bug
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Attiva
- Stack tecnologico
- typescript
- Ambito
- authentication, backend, security
Direzione di ricerca
Start with src/api.ts to trace how JWT_SECRET is used for signing and verification, then compare the related README_es.md section with .env.template. Done means the hardcoded secret is replaced by a required environment value, the template and teaching warning document that requirement, and a regression test covers rejection of tokens signed with MY_SECRET.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Hardcoded JWT secret MY_SECRET permits forged authentication cookies
Hello Lemoncode maintainers,
I understand that this repository contains an educational OAuth2 and JWT example. Could you please confirm whether MY_SECRET is intended only as a temporary teaching placeholder? Teaching examples should be especially careful with security defaults: otherwise, students may copy the pattern and reproduce the same vulnerability in real applications. Would you consider demonstrating a required high-entropy environment variable, adding it to .env.template, and explicitly warning that the placeholder must never be used in production?
The concise finding is below.
Summary
src/api.ts hardcodes the JWT signing key as MY_SECRET: api.ts#L20-L32. The code signs the authentication token with this value and places it in the authorization cookie: api.ts#L34-L47.
The same public value is used to verify the cookie token. The /api/user-profile endpoint trusts the verified id claim and returns the corresponding profile: api.ts#L50-L64.
Anyone who knows the repository can forge a valid JWT containing a known user ID and read that user’s profile without completing the Google OAuth flow. The current direct impact is unauthorized profile disclosure and authentication-cookie forgery. This report does not claim impact from routes that are not present in this example.
CVSS 3.1: 6.5 Medium (AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N), for a reachable deployment using this example.
CWE: CWE-321 — Use of Hard-coded Cryptographic Key.
Evidence
The root cause is explicit:
const JWT_SECRET = 'MY_SECRET'; // TODO: Move to env variable
The README reproduces the same hardcoded key and still marks moving it to an environment variable as a TODO: README_es.md#L341-L356.
The teaching .env.template contains Google credentials but no JWT_SECRET field: .env.template#L1-L4.
The README describes the intended flow as storing the authenticated user ID in a JWT cookie, verifying it, and loading the profile by that ID: README_es.md#L172-L182.
Offline PoC
This generates a token locally only. It does not start the application or contact any online instance.
// Run in an isolated directory with jsonwebtoken installed.
const jwt = require('jsonwebtoken');
const token = jwt.sign(
{ id: 1 },
'MY_SECRET',
{ algorithm: 'HS256' },
);
console.log(token);
For an authorized test instance, the generated token would be supplied as:
curl -H "Cookie: authorization=$TOKEN" \
https://<authorized-test-instance>/api/user-profile
The request above is a test template only; it was not executed against the project or any third-party service.
Impact
An attacker who can reach an instance using this code can:
- forge the
authorizationJWT cookie without completing Google OAuth; - choose a known user ID in the JWT payload;
- retrieve the matching profile through
/api/user-profile, including the profile fields returned by the repository.
If this authentication pattern is copied into additional protected routes, the same forged cookie can cross those authorization boundaries. That broader impact is not asserted for the current example because the finding is limited to the code shown above.
Remediation
- Remove the hardcoded
MY_SECRETvalue. - Load
JWT_SECRETfrom the environment or a secret manager and fail startup when it is missing or empty. - Add
JWT_SECRETto.env.templateas a clearly marked high-entropy placeholder, for exampleJWT_SECRET=replace-with-a-high-entropy-secret. - Add a README warning that the example value must never be used outside local teaching.
- Rotate the secret after deployment and invalidate tokens signed with
MY_SECRET. - Add a regression test proving that a token signed with
MY_SECRETis rejected by the production configuration.
Related works
Comparable public reports and fixes involving hardcoded or weak authentication secrets include:
- GHSA-cwj8-7gp2-ggcw
- GHSA-mqq6-462x-jxmm
- GHSA-cc4f-hjpj-g9p8
- GHSA-c8m8-3jcr-6rj5
- LibreChat default-credential removal commit
- GHSA-gc24-px2r-5qmf
- GHSA-4m32-cjv7-f425
- GHSA-v9q6-fm48-rx74
This report is part of my ongoing security research. If anything is unclear or you would like to discuss the finding, please feel free to tag me or contact me at any time. I would be genuinely pleased to contribute, even in a small way, to improving the security of this project and its teaching material.
- Lingua principale
- TypeScript
- Stelle
- 185
- Fork
- 99
- Merge medio
- 1m
- PR unite (30g)
- 2
Preparare l'ambiente
Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di Lemoncode/master-frontend-lemoncode
-
[Infrastructure] Migrate to `main` branch and ditch `master`Forse di nuovo libera @brauliodiez l’ha presa 714 giorni fa e non c’è nessuna pull request aperta. Aperta
Lemoncode/master-frontend-lemoncode#787 · 1 commento · 1 assegnatario ·
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 55/100
-
[Layout] Responsive and SassAperta
Difficoltà 5/5 Più di una settimana Idoneità per principianti 15/100
-
[Layout] CSS GridAperta
Difficoltà 5/5 Più di una settimana Idoneità per principianti 15/100
-
[Layout] FlexboxAperta
Difficoltà 5/5 Più di una settimana Idoneità per principianti 10/100
Tutte le issue di Lemoncode/master-frontend-lemoncode
Issue simili
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
aiko-chan-ai/DiscordBotClient#380 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
vercel/ai-elements#507 ·
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
I maintainer di solito rispondono entro 2 giorni
-
Difficoltà 2/5 Mezza giornata Idoneità per principianti 84/100
anaclumos/qa-interns#148 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno