Skip to content

fix(worker): store iv as hex string instead of raw bytes#76

Merged
Androz2091 merged 1 commit intomainfrom
fix/iv-bytea-leak
May 1, 2026
Merged

fix(worker): store iv as hex string instead of raw bytes#76
Androz2091 merged 1 commit intomainfrom
fix/iv-bytea-leak

Conversation

@Androz2091
Copy link
Copy Markdown
Member

Summary

The worker was writing `os.urandom(16)` (raw bytes) into the `SavedPackageData.iv` column, which is declared as `String(255)` in db.py:17. SQLAlchemy/psycopg2 serialize bytes-into-text using PostgreSQL's BYTEA literal — `\x` followed by the hex bytes — and that string flowed unchanged to the client through `/blob`'s JSON response (`"iv": "\\x5d05..."`).

The frontend then handed that to `decryptPackageBlob`, which interpreted it as a hex IV. The leading `\x` is not valid hex, so AES-CBC decryption either threw or produced garbage. The loading page hung forever — backend showed `PROCESSED`, but the data fetcher never resolved, so the UI stayed on the processing screen.

Spotted because PR #74's first real package finished server-side but the UI reported it as still processing — a curl on `/blob` revealed the malformed IV.

Fix

  • Worker (`tasks.py`): write `iv.hex()` instead of `iv`. Clean 32-char hex string in the column.
  • API (`app.py`): drop the defensive `bytes-to-hex` branch in `/blob`. With the worker writing hex directly, `row.iv` is always already a string — the defensive code was actually masking the real bug (it only kicked in if the value were bytes, but here it's a string starting with `\x`).

No frontend change. The frontend is correct — it expects a hex string and the server should always provide one.

Migration

Existing rows written before this fix still carry the `\x` prefix in the `iv` column and will continue to fail decryption. To recover them:

```bash
scripts/reprocess.sh ""
```

Reprocessing deletes the bad row + S3 blob and re-runs the worker, which now stores a clean hex IV.

I won't backfill — there's only one such row in production right now (the test package from the Fargate validation), and reprocessing it is a one-liner.

Test plan

  • Merge → CI deploys (the deploy.yml already updates both Lambdas + the Fargate task definition).
  • Run `scripts/reprocess.sh` on the existing test package.
  • Confirm `/blob` returns `iv` as a clean 32-char hex string (no `\x` prefix).
  • Confirm the loading page advances past "processing" and redirects to `/overview`.

The SavedPackageData.iv column is String(255), but the worker was
writing the raw bytes returned by os.urandom(16). SQLAlchemy/psycopg2
serialize bytes-into-text as PostgreSQL's BYTEA literal "\x..." +
hex, which then flowed straight to the client through /blob's JSON
response. The frontend tried to use that as a hex IV, AES-CBC produced
garbage, and the loading screen was stuck on "processing" forever.

Fix: write iv.hex() at the worker. App's /blob handler now just
returns row.iv as-is — the previous defensive bytes-to-hex check was
masking the real bug.

Existing rows written before this fix still carry the "\x..." prefix
and need to be reprocessed (delete + POST /process).
@Androz2091 Androz2091 merged commit de1c31d into main May 1, 2026
1 check passed
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