Allowlist huggingface-hub's http_backoff loop so Security audit stops failing by danielhanchen · Pull Request #9252 · unslothai/unsloth · GitHub
Skip to content

Allowlist huggingface-hub's http_backoff loop so Security audit stops failing - #9252

Merged
danielhanchen merged 2 commits into
mainfrom
fix-security-audit-hf-backoff
Aug 19, 2026
Merged

Allowlist huggingface-hub's http_backoff loop so Security audit stops failing#9252
danielhanchen merged 2 commits into
mainfrom
fix-security-audit-hf-backoff

Conversation

@danielhanchen

Copy link
Copy Markdown
Member

Security audit has been red on every main commit since fc325f4, on all three pip scan-packages legs, with a single un-baselined CRITICAL:

C2 polling/beaconing loop detected
huggingface-hub  huggingface_hub/utils/_http.py
L461:     while True: sha256:b08763160ae6f4d638b32f3cc333c4ac4fc0344988c9506efed65e0ef03ec2d5

No repo commit caused it

fc325f4 changed workflows and one test file, nothing that resolves a dependency. What moved is upstream: the resolved huggingface-hub came off the 0.x line. Reproduced locally against each version, and the sha256 matches CI's byte for byte:

version utils/_http.py flagged
0.36.2 no
1.26.1 yes
1.27.0 yes
1.28.0 yes

It is a false positive

The code is http_backoff: it counts nb_tries against max_retries, sleeps with exponential backoff between attempts, and raises once the budget is spent. A bounded retry, not a beacon.

RE_C2_POLLING is while True .* sleep .* requests\. under re.DOTALL, which cannot tell those two shapes apart. So the file is allowlisted rather than the check weakened — consistent with the 51 CRITICALs already reviewed this way, four of them this same check in this same package.

How the entry was produced

With the scanner's own --write-baseline, so the evidence_hash is computed by the code that will match it, then merged as a single entry rather than by regenerating the file. A full rewrite re-sorts it and turns a one-entry review into a 731-line diff. Nothing else was added or removed; asserted on both directions of the key set. The diff is 8 lines.

Worth knowing for next time

This file now holds four entries for this check — L298, L461, L462 and L461 again — one per revision of the loop huggingface-hub has shipped. That is the mechanism working as designed: the key is digest-pinned, so every edit reopens the finding and asks for a fresh review. The cost is that a hub release touching those thirty lines turns Security audit red again. The new test says so in place, so the next one gets read as upstream drift rather than a break.

Guard

test_the_hf_backoff_suppression_is_narrow covers the part that actually matters about silencing a CRITICAL in a file that already speaks HTTP:

  • every entry stays pinned to reviewed code (sha256: present, evidence_hash explicit),
  • none are duplicated,
  • a beaconing loop appended to the same file under the same check produces a different key rather than inheriting the suppression.

Three mutations confirmed red: drop the entries, strip the sha256 pin, duplicate an entry.

Verification

  • scan_packages.py huggingface-hub==1.28.0: 1 CRITICAL → 0, exit 1 → 0.
  • tests/security/test_scan_packages.py: 123 passed.

… failing

Security audit has been red on every main commit since fc325f4, on all three
pip scan-packages legs, with a single un-baselined CRITICAL:

  C2 polling/beaconing loop detected
  huggingface-hub  huggingface_hub/utils/_http.py
  L461:     while True: sha256:b087631...

No repo commit caused it. fc325f4 changed workflows and one test file, nothing
that resolves a dependency. What moved is upstream: the resolved huggingface-hub
came off the 0.x line, and 1.26.1, 1.27.0 and 1.28.0 all carry this loop while
0.36.2 does not. Reproduced locally against each of those versions, and the sha256
matches CI's byte for byte.

The code is `http_backoff`: it counts nb_tries against max_retries, sleeps with
exponential backoff between attempts, and raises once the budget is spent. A
bounded retry, not a beacon. RE_C2_POLLING is `while True .* sleep .* requests\.`
under re.DOTALL, which cannot tell those apart, so the file is allowlisted rather
than the check weakened -- consistent with the 51 CRITICALs already reviewed this
way, four of them this same check in this same package.

Added with the scanner's own --write-baseline so the evidence_hash is computed by
the code that will match it, then merged as a single entry rather than by
regenerating: a full rewrite re-sorts the file and turns a one-entry review into a
731-line diff. Nothing else added or removed, asserted on both directions of the
key set.

Worth recording: this file now holds FOUR entries for this check, at L298, L461,
L462 and L461 again, one per revision of the loop huggingface-hub has shipped.
That is the mechanism working -- the key is digest-pinned, so every edit reopens
the finding for review -- but it means a hub release touching those thirty lines
turns Security audit red again. The new test says so, so the next one is read as
upstream drift rather than a break.

test_the_hf_backoff_suppression_is_narrow guards the part that actually matters
about silencing a CRITICAL in a file that already speaks HTTP: every entry stays
pinned to reviewed code, none are duplicated, and a beaconing loop appended to the
same file under the same check produces a different key rather than inheriting the
suppression. Three mutations checked red (drop the entries, strip the sha256 pin,
duplicate an entry).

Verified: scan of huggingface-hub 1.28.0 goes 1 CRITICAL to 0, exit 1 to 0.
tests/security/test_scan_packages.py 123 passed.
@chatgpt-codex-connector

Copy link
Copy Markdown

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