fix: resolve node references only for a trusted document - #77
Merged
Merged
Conversation
added 2 commits
September 16, 2026 03:48
Reading a node reference back makes two fields of the target struct point at the same object. That is what the round trip of a cyclic object needs, but a document from an untrusted source could use it the same way. The parser now reads the ___jnid_ key and a bare <N> value as node references only for a document passed to ParseTrusted. Parse, ParseString and ParseStream keep them as ordinary values, so a forged reference becomes a plain string that fails to unmarshal into the field it targets. Marshal is unchanged: it needs this syntax to terminate on a cyclic object.
Resolve the conflicts in jsonutils.go and parse_session.go. Move the tests that exercise node references in parse_test.go, jsonpointer_test.go and robust_test.go to the trusted entry point, which is where references are resolved now.
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.
背景
Marshal对循环对象写入节点引用语法(对象内的___jnid_键 + 裸<N>值),使循环能够终止。解析器此前无条件识别这套语法并把它还原成对象引用。还原一个引用会让目标结构体的两个字段指向同一个对象。循环对象的往返需要这个行为,但来自不可信来源的文档同样可以利用它 —— 构造
{"a":{"___jnid_":1,...},"c":<1>}就能让a与c两个字段互为别名,且不产生任何错误。合法往返与伪造文档在结构上完全同形,无法从文档本身区分,因此改为按来源区分。
变更
新增受信任入口:
Parse/ParseString/ParseStream不再把___jnid_与裸<N>当作引用:<N>按既有规则回落为普通字符串,反序列化到原目标字段时明确报类型错误,不会静默产生别名___jnid_作为普通键保留在对象里Marshal不变 —— 循环对象必须有这套语法才能终止。破坏性变更
Marshal → String → Parse → Unmarshal)ParseTrusted系列___jnid_/<N>)Marshal(x).Unmarshal(&y))测试
新增
node_reference_test.go:TestNodeReferenceNotResolved:默认入口下<1>是普通字符串、___jnid_是普通键、两字段不互为别名TestNodeReferenceDoesNotAlias:伪造引用不得产生别名TestMarshalUnmarshalKeepsCycle:内存内往返仍能还原环TestParseTrustedResolvesReference:受信任入口正常还原引用并消费保留键TestParseTrustedRoundTrip:循环图经文本往返仍还原marshal_test.go的TestMarshalLoop有 1 行改动(ParseString→ParseTrustedString),该用例本就断言循环图的文本往返,属受信任场景。go test ./...全量通过。合并提示
本 PR 与 #69 在
jsonutils.go同样两行存在冲突(parseJSONValue的<N>判断、parseDict的___jnid_分支)。解析方式:采用本 PR 的版本,其中已包含 #69 的len(val) > 1边界检查与 comma-ok 断言。