Skip to content

bug: remove hard-coded default [REDACTED SECRET] credential, hash passwords (sfind-1a5ebd13) - #1100

Open
devin-ai-integration[bot] wants to merge 6 commits into
mainfrom
devin/sfind-1a5ebd13-remove-default-admin-credential
Open

devin-ai-integration[bot] wants to merge 6 commits into
mainfrom
devin/sfind-1a5ebd13-remove-default-admin-credential

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

Resumo

Corrige o finding sfind-1a5ebd13 (alta): ao subir, o mongoose-db.js criava [REDACTED SECRET]@snyk.io com a senha publicada no repositório (SuperSecretPassword) e a gravava em texto puro. Com isso, quem tivesse lido o repo conseguia fazer login como [REDACTED SECRET] via POST /login em qualquer deploy que manteve o padrão.

O que muda:

  • Sem senha embutida no código. O [REDACTED SECRET] só é criado quando ADMIN_PASSWORD está definido (usuário fixo [REDACTED SECRET]@snyk.io; não há mais ADMIN_USERNAME, para evitar que um [REDACTED SECRET] antigo continue ativo após renomear). Se a variável não existir, nenhum [REDACTED SECRET] é criado. O valor de ADMIN_PASSWORD prevalece: se ele mudar, a senha é rotacionada na próxima inicialização.
  • Hash scrypt (crypto.scrypt nativo, salt aleatório de 16 bytes) em password-hash.js, aplicado por um hook pre('save') em User.
  • Login (routes/index.js): User.findOne({ username }) + verifyPassword (timingSafeEqual). A senha deixou de entrar na query e precisa ser string. Isso também fecha o login por {"$gt": ""}.
  • Bancos já existentes: antes do seed, a inicialização roda
    User.update({ password: { $exists: true, $not: /^scrypt\$/ } }, { $unset: { password: 1 } }, { multi: true })
    e assim remove a senha SuperSecretPassword (e qualquer outra em texto puro) que deploys antigos já gravaram. Essas senhas não serviriam mais para login de qualquer forma.
  • sarif.json (SARIF estático enviado pelo workflow snyk code manual test): removido o resultado javascript/Sqli do login, que foi corrigido, e os demais resultados de routes/index.js foram re-ancorados nas novas linhas (+1/+5). Sem isso, o check SnykCode abre alertas novos.
  • docker-compose.yml / app.json repassam ADMIN_PASSWORD. O README e exploits/nosql-exploits.sh agora usam $ADMIN_PASSWORD.

Mudança de comportamento / contrato: o login de [REDACTED SECRET] com a senha publicada deixa de funcionar. Para ter [REDACTED SECRET] é preciso subir com ADMIN_PASSWORD=.... Os passos do README que demonstram a NoSQL injection no login foram atualizados, porque ela foi corrigida junto.

Duplicata: os 2 primeiros commits são cherry-pick da branch devin/1793687194-hash-[REDACTED SECRET]-password (e há outras branches/PRs antigos com a mesma ideia, como o #629 para sfind-3edb37df). Só um deve ser mergeado. Este PR acrescenta a limpeza das senhas em texto puro já gravadas e testes tap.

Como testar

O Mongoose 4.2.4 não conversa com o mongod 7 local (OP_QUERY removido) e a imagem mongo:3 não está disponível. Por isso o app.js real roda com um shim em memória que respeita $gt/$exists/$not/$unset e executa os hooks de save do schema.

e2e.sh <checkout> <label> <porta> [ADMIN_PASSWORD] faz POST /login com a credencial publicada:

cenário SuperSecretPassword ADMIN_PASSWORD {"$gt":""} linha User final
main, banco novo 302 /[REDACTED SECRET] n/a 302 /[REDACTED SECRET] senha em texto puro
fix, banco novo, sem env 401 n/a 401 nenhum [REDACTED SECRET]
fix, banco novo, ADMIN_PASSWORD 401 302 /[REDACTED SECRET] 401 scrypt$...
fix, banco legado (texto puro), sem env 401 n/a 401 senha removida
fix, banco legado, ADMIN_PASSWORD 401 302 /[REDACTED SECRET] 401 scrypt$...
  • O filtro $exists/$not: /^scrypt\$/ também foi verificado contra um mongod 7.0 real (driver 3.5.9): apaga só a senha em texto puro e mantém o hash e o usuário sem senha.
  • node_modules/.bin/tap tests/password-hash.test.js: 2/2 (salt aleatório, verify ok/erro, rejeita valor em texto puro gravado e senha que não é string).

Devin-Org: engineering

Link to Devin session: https://devin-gtm.devinenterprise.com/sessions/86bbea1031d64698a0a32d268e61bd99
Open in Devin Desktop: https://devin-gtm.devinenterprise.com/desktop/session/86bbea1031d64698a0a32d268e61bd99?variant=devin


Devin Review

Status Commit
⚪ Not started —

Run Devin Review

Enable auto-review to review your pull requests automatically.

Devin Review (Staging)


Devin Review

Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…hash tests

Existing deployments still hold the previously published admin password
in plaintext. Unset any User password that is not an scrypt hash before
seeding the admin from ADMIN_PASSWORD.

Refs: sfind-1a5ebd13023045bdaab4dabc8cfa0342
@devin-ai-integration

Copy link
Copy Markdown
Author

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

github-advanced-security[bot]

This comment was marked as resolved.

…ykCode SARIF

Refs: sfind-1a5ebd13023045bdaab4dabc8cfa0342
…ine numbers

Refs: sfind-1a5ebd13023045bdaab4dabc8cfa0342

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Devin Review

Comment thread routes/index.js
if (err) return next(err);
if (!user) return res.status(401).send();

passwordHash.verifyPassword(req.body.password, user.password, function (err, verified) {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟨 Password guesses exhaust scrypt workers

Repeated requests for an existing username make verifyPassword run scrypt on every guessed password. Without login rate limiting, unauthenticated clients can saturate crypto workers and delay legitimate requests.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid concern, but I'm leaving it out of this PR on purpose. This PR fixes the hard-coded [REDACTED SECRET] credential (sfind-1a5ebd13).

  • /login had no rate limiting or lockout before this change either. Unlimited guessing was already possible; it was just cheaper per request.
  • crypto.scrypt is async and runs on the libuv threadpool, so it doesn't block the event loop. Heavy traffic can still fill the 4 default workers, which is the amplification you describe.
  • The right fix is per-IP/per-account throttling, ideally at the proxy or with express-rate-limit. That's a new dependency and a policy decision (limits, lockout, storage across instances), so it should be its own change rather than part of a credential fix.

I'm leaving this thread open so the maintainers can decide whether to track login throttling as a follow-up.

Written by Devin

Comment thread mongoose-db.js Resolved
…snyk.io

Changing ADMIN_USERNAME created a second admin and left the old one able
to log in (Devin Review). Keep a single fixed admin account.

Refs: sfind-1a5ebd13023045bdaab4dabc8cfa0342
@devin-ai-integration

Copy link
Copy Markdown
Author

Teste no navegador (app real com um banco MongoDB em memória, porque o Mongoose 4.2.4 não conecta ao MongoDB 7):

  • main: a senha publicada entra no [REDACTED SECRET] (302 para /[REDACTED SECRET]).
  • Com esta PR: a senha publicada recebe 401 em todos os cenários (banco novo ou legado, com ou sem ADMIN_PASSWORD). O valor de ADMIN_PASSWORD dá acesso ao /[REDACTED SECRET].

Fluxo de login

Senha publicada recusada Login com ADMIN_PASSWORD
401 [REDACTED SECRET]

O harness e2e foi executado de novo no ae6f190 (remoção de ADMIN_USERNAME) com os mesmos resultados. tests/password-hash.test.js passa, e os 5 checks de CI estão verdes.

Written by Devin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant