routers/upload.py compares the node API key with a plain != (key_doc.get("api_key") != credentials.credentials), which is not constant-time.
A minor timing side-channel on /upload. Worth fixing mainly because it is the exact class of issue the newer MQTT auth code (enrollment.py, dynsec.py) was explicit about avoiding with secrets.compare_digest — so the codebase currently contradicts itself. One-line fix.
`routers/upload.py` compares the node API key with a plain `!=` (`key_doc.get("api_key") != credentials.credentials`), which is not constant-time.
A minor timing side-channel on `/upload`. Worth fixing mainly because it is the exact class of issue the newer MQTT auth code (`enrollment.py`, `dynsec.py`) was explicit about avoiding with `secrets.compare_digest` — so the codebase currently contradicts itself. One-line fix.
Fixed in 5355095. /upload now uses secrets.compare_digest, matching what enrollment.py and dynsec.py already did for the same class of credential.
One thing the fix added beyond the one-liner: a missing api_key field is coalesced to "" before the comparison. compare_digest(None, ...) raises TypeError, which would have turned a malformed node_keys document into a 500 instead of a 401.
Fixed in `5355095`. `/upload` now uses `secrets.compare_digest`, matching what `enrollment.py` and `dynsec.py` already did for the same class of credential.
One thing the fix added beyond the one-liner: a missing `api_key` field is coalesced to `""` before the comparison. `compare_digest(None, ...)` raises `TypeError`, which would have turned a malformed `node_keys` document into a 500 instead of a 401.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
routers/upload.pycompares the node API key with a plain!=(key_doc.get("api_key") != credentials.credentials), which is not constant-time.A minor timing side-channel on
/upload. Worth fixing mainly because it is the exact class of issue the newer MQTT auth code (enrollment.py,dynsec.py) was explicit about avoiding withsecrets.compare_digest— so the codebase currently contradicts itself. One-line fix.Fixed in
5355095./uploadnow usessecrets.compare_digest, matching whatenrollment.pyanddynsec.pyalready did for the same class of credential.One thing the fix added beyond the one-liner: a missing
api_keyfield is coalesced to""before the comparison.compare_digest(None, ...)raisesTypeError, which would have turned a malformednode_keysdocument into a 500 instead of a 401.