carlos / platform Public

release: a proof policy with any data after the object is an error (H1)

Decoder.More() is false before a stray '}' or ']', so {"schema":1}} parsed as a policy with no requirements. A second Decode must now return io.EOF; anything else is a parse error and the gate stays closed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 1358ba34dc828928dbbb9b223981ab53f62c5141 parent 7b2cad1
2 files changed, +14 −1
  • internal/release/proofpolicy.go +4 −1
  • internal/release/proofpolicy_test.go +10 −0
diff --git a/internal/release/proofpolicy.go b/internal/release/proofpolicy.go
index b4382d023..b1c25d317 100644
--- a/internal/release/proofpolicy.go
+++ b/internal/release/proofpolicy.go
@@ -19,6 +19,7 @@ import (
"encoding/json"
"errors"
"fmt"
+ "io"
"os"
"path/filepath"
"time"
@@ -77,7 +78,9 @@ func ParseProofPolicy(b []byte) (*ProofPolicy, error) {
if err := dec.Decode(&p); err != nil {
return nil, fmt.Errorf("does not parse: %v", err)
}
- if dec.More() {
+ // More() is false before a stray '}' or ']', so it cannot prove the end
+ // of input; only a second Decode returning io.EOF does.
+ if err := dec.Decode(&json.RawMessage{}); err != io.EOF {
return nil, fmt.Errorf("does not parse: data after the policy object")
}
if p.Schema != 1 {
diff --git a/internal/release/proofpolicy_test.go b/internal/release/proofpolicy_test.go
index 908af8e24..176860466 100644
--- a/internal/release/proofpolicy_test.go
+++ b/internal/release/proofpolicy_test.go
@@ -66,9 +66,19 @@ func TestProofPolicyUnparseableIsAnError(t *testing.T) {
"relative key": `{"schema":1,"prove":{"apps":["console"],"prover":"dev","after":"15m","key_file":"proving.key"}}`,
"no apps": `{"schema":1,"prove":{"apps":[],"prover":"dev","after":"15m","key_file":"/k"}}`,
"trailing junk": `{"schema":1} {}`,
+ "trailing }": `{"schema":1}}`,
+ "trailing ]": `{"schema":1}]`,
+ "trailing word": `{"schema":1} x`,
} {
if _, err := ParseProofPolicy([]byte(body)); err == nil {
t.Fatalf("%s: parsed, want an error", name)
}
}
}
+
+// Trailing whitespace is still the end of input.
+func TestProofPolicyTrailingWhitespaceParses(t *testing.T) {
+ if _, err := ParseProofPolicy([]byte("{\"schema\":1}\n\n \t")); err != nil {
+ t.Fatal(err)
+ }
+}