Skip to content

fix(security): floor litellm/wandb/lxml past known CVEs; relax stale click cap#1507

Open
nicgupta-nvidia wants to merge 6 commits into
mainfrom
fix/security-dependency-floors
Open

fix(security): floor litellm/wandb/lxml past known CVEs; relax stale click cap#1507
nicgupta-nvidia wants to merge 6 commits into
mainfrom
fix/security-dependency-floors

Conversation

@nicgupta-nvidia

@nicgupta-nvidia nicgupta-nvidia commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

What

Four dependency-only security fixes (no code changes):

Package Before After Why
litellm[caching] ==1.83.14 ==1.84.10 GHSA-4xpc-pv4p-pm3w (Critical) — 1.83.x sends the configured API key to an arbitrary attacker-controlled Host header; fixed in 1.84.0. Minimal exact-pin jump.
wandb unpinned >=0.27.1 Older wheels bundle a wandb-core Go binary built with golang.org/x/crypto 0.50.0 + Go 1.26.2 stdlib carrying 7 Critical / 13 High CVEs (x/crypto, Go stdlib, x/net, go-git, go-billy). 0.27.1 is the first release embedding patched x/crypto 0.52.0 (verified via Go buildinfo on both arches).
click < 8.2.0 cap removed The cap guarded against the typer×click-8.2 make_metavar break (ai-dynamo/dynamo#1039) — closed 2025-06-26, fixed in typer ≥0.16. wandb>=0.27.1 hard-requires click>=8.2, and this repo's requires-python >=3.10 satisfies click 8.2's floor.
typer >= 0.13 >= 0.16 Guarantees the click-8.2-compatible typer alongside the cap removal.
lxml (stem extra) unpinned >=6.1.0 GHSA-vfmq-68hx-4jfw (High); unpinned installs were resolving to vulnerable 5.4.0 in container builds.

Also updates the pyproject.toml override comment that referenced the old litellm==1.83.14 httpx pin.

Validation

  • uv pip compile core/requirements.txt requirements/pipeline.txt (Python 3.10, with the repo's httpx[http2]>=0.28.1 / urllib3>=2.6.3 overrides) resolves cleanly: litellm 1.84.10, wandb 0.28.0, click 8.4.2, typer 0.26.8, httpx 0.28.1.
  • uv pip compile requirements/stem.txt resolves with lxml 6.1.1.
  • Runtime smoke on the resolved set: litellm and wandb import clean; a typer CLI --help render (the exact Parameter.make_metavar crash path from dynamo#1039) passes under click 8.4.

Tests

tests/test_dependency_functional.py adds functional coverage on top of the static pin guard in tests/test_requirements_versions.py — it drives the bumped packages through NeMo-Skills' own code paths (CPU-only, hermetic: no sandbox, no live endpoint, no API keys), so a resolve to a behavior-divergent version fails CI rather than a production run. 13 tests, all green locally on the resolved set (litellm 1.84.10 / typer 0.26.8 / click 8.4.2 / wandb 0.28.0 / lxml 6.1.1):

  • litellmOpenAIModel.litellm_kwargs binds the api_key to the configured base_url/api_base only (a regression guard for GHSA-4xpc-pv4p-pm3w, the key-to-arbitrary-Host leak this bump fixes); generate_async calls litellm.acompletion with those credentials and parses the 1.84 response; the imported litellm exception/type surface still exists.
  • typer/click — the ns CLI --help + per-command help render Parameter.make_metavar (the click 8.2 break typer>=0.16 fixes), and unknown commands are usage errors.
  • wandblog_random_samples matches the wandb 0.28 init/save/summary/finish contract, plus a real offline init/finish cycle with no account.
  • lxmlimportorskip-guarded real parse.

Coverage caveat (lxml): lxml ships only in the optional stem extra, not in .[dev], so test_lxml_parses_html is skipped in the existing unit-tests CI job (which installs -e .[dev]) — it does not give live CI signal there. The lxml>=6.1.0 floor remains covered by the static assertion in test_requirements_versions.py; to exercise lxml functionally in CI, add .[stem] to the unit-tests install. The other 12 tests run and give real signal in the current job.

Notes

  • Deliberately kept separate from feat: add a Ray Jobs API execution backend #1479 (feature PR) — this is release-blocking security hygiene on the shared dependency set.
  • nltk (GHSA-p4gq-832x-fm9v) is intentionally NOT floored here: the advisory designates no patched version (first_patched: null), so a floor would only silence scanners without a verified fix.

Summary by CodeRabbit

  • Bug Fixes

    • Updated dependency pins/minimums for improved security posture and compatibility, including litellm[caching], wandb, and lxml.
    • Adjusted CLI/experimentation constraints by removing the click upper pin and raising the typer minimum for compatibility.
  • Tests

    • Added regression coverage to prevent reintroducing insecure or conflicting dependency constraints.
    • Added CPU-only functional tests covering model integration, CLI help rendering, offline wandb behavior, and HTML parsing.
  • Documentation

    • Refreshed dependency-related comments to match the current constraint sources.

…click cap

- litellm[caching] 1.83.14 -> 1.84.10: GHSA-4xpc-pv4p-pm3w (Critical) —
  1.83.x leaks the API key to an arbitrary attacker-controlled Host header;
  fixed in 1.84.0. Minimal exact-pin jump; resolves with the existing
  httpx[http2]>=0.28.1 override (litellm 1.84.10 needs httpx>=0.28.0).
- wandb -> >=0.27.1: the bundled wandb-core Go binary in older wheels ships
  golang.org/x/crypto 0.50.0 + Go 1.26.2 stdlib with 7 Critical / 13 High
  CVEs (incl. GHSA-x527-x647-q7gg et al.); 0.27.1 is the first release
  embedding patched x/crypto 0.52.0 (verified on both arches).
- click < 8.2.0 cap removed + typer >= 0.16: the cap guarded against the
  typer/click-8.2 make_metavar break (ai-dynamo/dynamo#1039, closed
  2025-06-26, fixed in typer >=0.16); wandb>=0.27.1 requires click>=8.2,
  and requires-python >=3.10 satisfies click 8.2's floor.
- lxml -> >=6.1.0 (stem extra): GHSA-vfmq-68hx-4jfw (High).

Validation: uv pip compile of core+pipeline (py3.10, with the pyproject
overrides) resolves cleanly — litellm 1.84.10 / wandb 0.28.0 / click 8.4.2 /
typer 0.26.8 / httpx 0.28.1; stem extra resolves with lxml 6.1.1. Runtime
smoke on the resolved set: litellm/wandb import clean; typer --help
rendering (the exact make_metavar crash path) passes under click 8.4.

Signed-off-by: Nick Gupta <nicgupta@nvidia.com>
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 3e944c6c-053d-428c-8ba2-031fd9573078

📥 Commits

Reviewing files that changed from the base of the PR and between a4caa68 and 2b52ca9.

📒 Files selected for processing (1)
  • requirements/stem.txt
💤 Files with no reviewable changes (1)
  • requirements/stem.txt

📝 Walkthrough

Walkthrough

Dependency constraints were updated across core, pipeline, stem, and test requirements, alongside a pyproject.toml comment. New tests validate requirement specifications and exercise litellm, Typer, wandb, and lxml compatibility.

Changes

Dependency security and compatibility updates

Layer / File(s) Summary
Dependency requirement updates
core/requirements.txt, requirements/pipeline.txt, requirements/stem.txt, requirements/common-tests.txt, pyproject.toml
Updated litellm, wandb, typer, click, lxml, and Python-version-specific TOML requirements, and revised the litellm httpx override comment.
Requirement regression tests
tests/test_requirements_versions.py
Added checks for dependency floors, pins, override dependencies, comments, and PEP 508 parseability.
Dependency functional compatibility tests
tests/test_dependency_functional.py
Added CPU-only coverage for litellm/OpenAI behavior, Typer CLI help, wandb offline operation, and lxml HTML parsing.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Suggested reviewers: gwarmstrong

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the dependency security floors and the click cap removal, which are the main changes in this PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/security-dependency-floors

Comment @coderabbitai help to get the list of available commands.

@nicgupta-nvidia nicgupta-nvidia self-assigned this Jul 9, 2026
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Note

Unit test generation is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

2 similar comments
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Note

Unit test generation is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Note

Unit test generation is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

✅ Unit tests committed locally. Commit: 07acd2ccc5aed23517851655d7112cfb704e9b7b

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

✅ Unit tests committed locally. Commit: e441a66eb09f718a0d49194cedc6abf56d9763e7

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

✅ Created PR with unit tests: #1508

CodeRabbit's test generation ran twice and committed two near-duplicate
suites (test_dependency_pins.py + test_requirements_versions.py) covering
the same pins. Keep the more robust one (operator-keyed specifier parsing
instead of next(iter(specifier)), which is order-fragile on multi-spec
requirements) and graft the three tests unique to the deleted file:
pyproject stale-comment guards, pipeline-lines-parseable, and the
wandb/typer click-comment consistency check.

Also:
- fix the copyright year (2026, not 2025)
- add tomli (python_version < 3.11) to common-tests.txt so the pyproject
  override tests actually RUN on the CI's Python 3.10 instead of
  silently skipping (tomllib is stdlib only from 3.11)
- add the missing trailing newline that failed the pre-commit
  end-of-file-fixer hook on the generated files

17 tests pass on Python 3.10 with the CI's -m 'not gpu' selection;
pre-commit (pinned ruff) clean.

Signed-off-by: Nick Gupta <nicgupta@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/test_requirements_versions.py (1)

95-96: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract a shared helper for specifier-floor extraction.

The {spec.operator: spec.version for spec in req.specifier} pattern is repeated across four test methods. A small helper reduces duplication and keeps the assertions consistent if the extraction logic ever needs to change (e.g., handling multiple specifiers of the same operator).

♻️ Proposed helper
+def _get_specifier(req: Requirement, operator: str) -> Version:
+    """Return the parsed Version for the given specifier operator, asserting it's present."""
+    specs = {spec.operator: spec.version for spec in req.specifier}
+    assert operator in specs, f"expected a '{operator}' specifier for {req.name}, got {req.specifier}"
+    return Version(specs[operator])
+
+
 class TestCoreRequirements:
     ...
     def test_litellm_pin_fixes_ghsa_4xpc_pv4p_pm3w(self):
         req, comment = _find_requirement(CORE_REQUIREMENTS, "litellm")
         assert "caching" in req.extras, "litellm[caching] extra must be preserved"
-
-        # Must be pinned to an exact version (== specifier) so the resolver is deterministic.
-        specs = {spec.operator: spec.version for spec in req.specifier}
-        assert "==" in specs, f"expected an exact pin for litellm, got specifier {req.specifier}"
-
-        pinned_version = Version(specs["=="])
+        pinned_version = _get_specifier(req, "==")

Also applies to: 113-114, 156-157, 178-179

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_requirements_versions.py` around lines 95 - 96, The specifier
extraction logic is duplicated across multiple test methods in the requirements
version tests, so add a shared helper for turning a requirement’s specifiers
into a usable mapping or floor value. Update the affected assertions in the test
class that currently build specs from req.specifier so they call this helper
instead, keeping the exact-pin checks unchanged while centralizing the
extraction behavior in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/test_requirements_versions.py`:
- Around line 95-96: The specifier extraction logic is duplicated across
multiple test methods in the requirements version tests, so add a shared helper
for turning a requirement’s specifiers into a usable mapping or floor value.
Update the affected assertions in the test class that currently build specs from
req.specifier so they call this helper instead, keeping the exact-pin checks
unchanged while centralizing the extraction behavior in one place.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 0ea160ee-449e-4976-b41b-78cdb3607f1a

📥 Commits

Reviewing files that changed from the base of the PR and between 49cd94e and 01bd214.

📒 Files selected for processing (2)
  • requirements/common-tests.txt
  • tests/test_requirements_versions.py

…ed deps

test_requirements_versions.py only asserts the pins statically. Add functional
coverage that drives litellm 1.84.10, typer/click, and wandb through NeMo-Skills'
own code paths (CPU-only, hermetic — no sandbox, no live endpoint, no API keys)
so a resolve to a behavior-divergent version fails CI, not a production run:

  * litellm: OpenAIModel.litellm_kwargs binds api_key to the configured
    base_url/api_base only (GHSA-4xpc-pv4p-pm3w regression), generate_async
    calls litellm.acompletion with those credentials and parses the 1.84
    response, and the imported litellm exception/type surface still exists.
  * typer/click: ns CLI --help + per-command help render Parameter.make_metavar
    (the click 8.2 break typer>=0.16 fixes) and unknown commands are usage errors.
  * wandb: log_random_samples matches the wandb 0.28 init/save/summary/finish
    contract, and a real offline init/finish cycle runs with no account.
  * lxml: importorskip-guarded real parse (optional stem extra).

Signed-off-by: Nick Gupta <nicgupta@nvidia.com>
Bring in #1509 (drop deleted vedas pin) so the sandbox image build — and
therefore this PR's CI — is unblocked.

Signed-off-by: Nick Gupta <nicgupta@nvidia.com>
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