Harden request auth and fix handler/source bugs - #11
Merged
Conversation
Security (server.go): - Add missing returns so the CIDR allowlist and decrypt-error paths actually block instead of falling through to serving the secret. - Bind ClientPubKey, timestamp, and a single-use nonce into the signed request (crypto.go, client.go) so a captured request can't be replayed with a substituted response key. - Reject stale/future requests outside MaxClockSkew and exact replays via a nonce cache swept by a background goroutine; add Server.Close to stop it. Correctness: - Env.Load: check the lowercase key so mixed-case services keep all secrets. - Onepass.Load: key services lowercase to match server lookup. - WriteRegistry: close the file handle. - Register: normalize name so re-registering updates instead of duplicating. Add server_test.go covering the rejection paths and the happy path.
Lock in the two correctness fixes that previously ran without assertions: - Env.Load retains all secrets for a mixed-case service name. - Register normalizes names so re-registering updates instead of duplicating.
turkosaurus
added a commit
that referenced
this pull request
Jun 28, 2026
Reconcile the remote-registry feature with the request-auth hardening that merged via #11. Conflicts resolved by keeping #10's architecture (Registry interface, registry polling, AllowRequestFunc policy, handlePost, body limit) and folding in #11's hardening: - server.go: nonce/timestamp binding via requestMessage, MaxClockSkew freshness check, seen-nonce replay cache + sweeper, Server.Close, drop decrypted-name log. CIDR enforcement is via #10's AllowCIDR policy (returns 403). - registry.go: #10's FileRegistry already carries the file-close and name normalization fixes; the old free functions are dropped. - tests: port the hardening regression tests and Register-dedup test to #10's FileRegistry/NewServer API.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Security fixes
wrote 403 but had no
return, so execution continued and the encryptedsecret was written to the response body. Added the missing returns (also on
the decrypt-error and per-entry verify-error paths).
name, so a captured request could be replayed with the attacker's own
ClientPubKeyto have the secret re-encrypted to them. The signed messagenow binds
name + ClientPubKey + timestamp + nonce.MaxClockSkew(30s) freshness window and aseen-nonce cache to reject exact replays within that window. Eviction runs in
a background sweeper (
Server.Closestops it).Correctness fixes
Env.Loadchecked the original-case key against a lowercase map, dropping allbut the last secret for mixed-case services.
Onepass.Loadkeyed services by original case; the server looks them uplowercased.
WriteRegistryleaked its file handle.Registerappended duplicate entries when re-registering a name with a.envsuffix.Tests
New
server_test.go: happy path, pubkey-substitution rejected, out-of-CIDRrejected, replay rejected, stale-timestamp rejected. Full suite passes under
-race.