render_error_paths_filetest.gno
2.17 Kb · 59 lines
1// PKGPATH: gno.land/r/test/rendererr
2package rendererr
3
4// Render is reachable unauthenticated via vm/qrender with an attacker-chosen
5// path. Two pre-existing defects on that path are covered here:
6// - the "invalid proposal id" error echoed the raw pid segment (strconv
7// quotes it but leaves markdown/HTML metachars), so a crafted pid injected
8// inline markup into a govDAO-branded page;
9// - a control byte in the query string made the pager's MustGetPageByPath
10// panic, aborting the landing-page render.
11// Both are now escaped / degraded-gracefully.
12
13import (
14 "strings"
15 "testing"
16
17 "gno.land/r/gov/dao"
18 "gno.land/r/gov/dao/impl/v0"
19 "gno.land/r/gov/dao/memberstore/v0"
20)
21
22const user address = "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5"
23
24func init(cur realm) {
25 memberstore.Get(0, cur).DeleteAll()
26 memberstore.Get(0, cur).SetTier(memberstore.T1)
27 memberstore.Get(0, cur).SetMember(memberstore.T1, user, memberstore.NewMember(3))
28 dao.UpdateImpl(cross(cur), dao.NewUpdateRequest(impl.NewGovDAO(), nil))
29}
30
31func main(cur realm) {
32 testing.SetOriginCaller(user)
33 testing.SetRealm(testing.NewUserRealm(user))
34
35 // 1. A non-numeric pid whose segment carries an inline-markdown payload.
36 // No '/', so it routes to {pid}; ParseInt fails and the error is escaped.
37 pout := dao.Render(cross(cur), "99[pwn](evil.example)")
38 println("payload is escaped, not a live link:",
39 strings.Contains(pout, `\[pwn\]`) && !strings.Contains(pout, "[pwn](evil.example)"))
40 println("still shows the invalid-id message:",
41 strings.Contains(pout, "Invalid proposal ID format"))
42
43 // Same on the /votes route.
44 vout := dao.Render(cross(cur), "88[x](evil.example)/votes")
45 println("votes route escapes it too:",
46 !strings.Contains(vout, "[x](evil.example)"))
47
48 // 2. A control byte in the query — url.Parse rejects it. The landing page
49 // must degrade to page 1, not panic.
50 lout := dao.Render(cross(cur), "?\x01")
51 println("control-byte query renders instead of panicking:",
52 strings.Contains(lout, "# GovDAO"))
53}
54
55// Output:
56// payload is escaped, not a live link: true
57// still shows the invalid-id message: true
58// votes route escapes it too: true
59// control-byte query renders instead of panicking: true