Dev.to AI πŸ€– Ai πŸ‘ 0 πŸ“– 2 min read

How uv add silently downgraded my pypdf security patch (and how I fixed it)

I merged two PRs to fix my dependency alerts on GitHub. Both had empty diffs. GitHub kept showing 11 open Dependabot alerts (10 high, 1 moderate). It was right, and I was wrong. When I dug into my terminal, I saw this:

How uv add silently downgraded my pypdf security patch (and how I fixed it)

 I merged two PRs to fix my dependency alerts on GitHub. Both had empty diffs.

GitHub kept showing 11 open Dependabot alerts (10 high, 1 moderate). It was right, and I was wrong.

When I dug into my terminal, I saw this:

text

  • pypdf==6.21.4
  • pypdf==6.21.1 My security patch was silently downgraded. Here is exactly why it happened and how to fix it.

Why did uv add downgrade my package?
I was working on CivicAI, an open-source PII redaction pipeline. I ran uv add presidio-analyzer presidio-anonymizer to add a new feature.

However, my local main branch was 5 commits behind origin/main.

pyproject.toml said "pypdf>=4.0".

My local uv.lock was stale and had pypdf 6.21.1 cached.

The resolver saw that 6.21.1 satisfied >=4.0, so it silently kept the vulnerable version.

I pushed the code. The tests passed. But the lockfile still had vulnerabilities.

The fix that actually sticks
You cannot just fix the lockfile; you have to fix the rules so it can't happen again.

Step 1: Sync your local repo

bash
git fetch origin
git rebase origin/main
Step 2: Force the upgrade

bash
uv lock --upgrade-package pypdf
Step 3: Raise the floor in pyproject.toml
Change "pypdf>=4.0" to "pypdf>=6.21.4".
This is the most important step. By raising the floor, even if a developer runs uv add on a stale lockfile, the resolver is forced to install 6.21.4 or higher.

Step 4: Declare your test dependencies
I also noticed my Presidio integration test was silently skipping on a fresh clone because presidio-analyzer wasn't in pyproject.toml.

toml

pyproject.toml

dependencies = [
"pypdf>=6.21.4",
"presidio-analyzer>=2.2.0",
"presidio-anonymizer>=2.2.0",
]
Result:

bash
$ gh api repos/sitara2007/CivicAI/dependabot/alerts --jq '[.[]|select(.state=="open")]|length'
0
Tests: 28 passed, 1 skipped (tested against real Postgres).

The Takeaway for Engineers
A merged PR isn’t a fix until the lockfile diff proves it. Always run git diff uv.lock before merging.

A skipped test is a signal, not a pass. If a test skips because a dependency isn't declared, your CI is lying to you.

Passing tests, dependency scanning, and code scanning answer different questions. You need all three.

I'm building CivicAI, an open-source PII redaction pipeline with a tamper-evident audit log. If your team sends sensitive text to LLMs, what's the hardest part of redaction today?

Repo: https://github.com/sitara2007/CivicAI

πŸ“° Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.