Skip to content

Require a PIN for web import and limit request size - #15

Merged
grifmo merged 2 commits into
mainfrom
fix/import-server
Oct 10, 2026
Merged

grifmo merged 2 commits into
mainfrom
fix/import-server

Conversation

@grifmo

@grifmo grifmo commented Oct 10, 2026

Copy link
Copy Markdown
Owner

Locks down the LAN web importer.

Issue Fix
#8 Unauthenticated writes Uploads and credential submissions need a 6-digit PIN shown on the TV (new per server start, constant-time compare, 5 wrong guesses lock it for 60 s). The page has a PIN field and sends it as X-UniVPN-PIN.
#9 No limits, weak validation Content-Length required and capped at 64 KB (checked before the body is read); at most 4 concurrent connections; configs must pass Config.parse; names capped at 80 chars

Traffic is still plain HTTP, so someone watching LAN traffic can read what's submitted. SECURITY.md and the README now describe the PIN and that limitation.

Testing

Unit: PinGuardTest (5 tests: accept, reject, lockout and expiry, reset on success, PIN format).

On the Android TV emulator (PIN read from the Profiles screen, port forwarded, requests with curl):

Request Result
GET form 200
Upload, no PIN 403
Upload, correct PIN, valid config 200, profile imported
Upload, correct PIN, invalid config 400 Not a valid WireGuard config: SYNTAX_ERROR in INTERFACE TOP_LEVEL
Upload, 100 KB 413
Upload, chunked (no Content-Length) 411
Credentials, no PIN 403
5th wrong PIN, then correct PIN 429, 429 (locked)
5th connection while 4 are held open closed (empty reply); works again once the idle ones time out

The page's script passes node --check. I didn't drive the form in a real browser; the requests above match what it sends.

🤖 Generated with Claude Code

grifmo and others added 2 commits October 10, 2026 10:06
The web import server accepted uploads and provider credentials from
anyone on the LAN, read request bodies of any size, served unlimited
concurrent connections, and only checked that a config contained
"[Interface]".

- Writes need a 6-digit PIN shown on the TV next to the address. It is
  new each time the server starts; five wrong guesses lock it for 60 s.
- Requests over 64 KB or without Content-Length are rejected before the
  body is read.
- At most 4 connections are served at once; extra ones are closed.
- Uploaded configs must parse with the WireGuard Config parser, and
  profile names are capped at 80 characters.

Traffic is still plain HTTP; SECURITY.md says so.

Fixes #8, fixes #9

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@grifmo
grifmo merged commit 44dac40 into main Oct 10, 2026
1 check passed
@grifmo
grifmo deleted the fix/import-server branch October 10, 2026 08:53
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