diff --git a/tests/samourai-crew/Dockerfile b/tests/samourai-crew/Dockerfile
index 85ec74c..51cec06 100644
--- a/tests/samourai-crew/Dockerfile
+++ b/tests/samourai-crew/Dockerfile
@@ -4,16 +4,17 @@ RUN apk add --no-cache bash jq
WORKDIR /tests
-COPY audit/ audit/
-COPY e2e/ e2e/
-COPY stress/ stress/
-COPY realms/ realms/
+COPY audit/ audit/
+COPY e2e/ e2e/
+COPY stress/ stress/
+COPY realms/ realms/
+COPY security-markdown/ security-markdown/
COPY run_tests.sh .
RUN chmod +x run_tests.sh \
- && find audit e2e stress -name "*.sh" -exec chmod +x {} +
+ && find audit e2e stress security-markdown -name "*.sh" -exec chmod +x {} +
-ENV REMOTES=http://127.0.0.1:26657
+ENV REMOTE=http://127.0.0.1:26657
ENV CHAINID=test
# Mnemonics are injected at runtime via docker run -e (see tests/samourai-crew/Makefile)
diff --git a/tests/samourai-crew/Makefile b/tests/samourai-crew/Makefile
index befb2ae..77c8cc6 100644
--- a/tests/samourai-crew/Makefile
+++ b/tests/samourai-crew/Makefile
@@ -17,7 +17,7 @@ MNEMONIC_3 := galaxy fire athlete egg three crane stone borrow thought cover sto
## list-funding-one-shot : print addresses and amounts to fund before one-shot tests
list-funding-one-shot:
- @echo "$(ADDR_1) 50000000ugnot $(ADDR_2) 15000000ugnot $(ADDR_3) 15000000ugnot"
+ @echo "$(ADDR_1) 150000000ugnot $(ADDR_2) 15000000ugnot $(ADDR_3) 15000000ugnot"
## list-funding-repeatable : print addresses and amounts to fund before repeatable tests
list-funding-repeatable:
diff --git a/tests/samourai-crew/run_tests.sh b/tests/samourai-crew/run_tests.sh
index 97b00d1..ec5581f 100755
--- a/tests/samourai-crew/run_tests.sh
+++ b/tests/samourai-crew/run_tests.sh
@@ -132,6 +132,19 @@ if [ "$MODE" = "one-shot" ] || [ "$MODE" = "all" ]; then
run_test "e2e_counter" /tests/e2e/e2e_counter.sh
run_test "e2e_mempool_stress" /tests/e2e/e2e_mempool_stress.sh
+ echo ""
+ echo "=== Security Markdown Audit (KNOWN VULNERABLE — gnolang/gno#5714) ==="
+ run_test "audit_md_title_leak" /tests/security-markdown/audit_md_title_leak.sh \
+ "Render() returns unsanitized title, see gnolang/gno#5714"
+ run_test "audit_md_html_inject" /tests/security-markdown/audit_md_html_inject.sh \
+ "Render() returns raw HTML tag, see gnolang/gno#5714"
+ run_test "audit_md_link_hijack" /tests/security-markdown/audit_md_link_hijack.sh \
+ "Render() returns hijacked link URL, see gnolang/gno#5714"
+ run_test "audit_md_blockquote" /tests/security-markdown/audit_md_blockquote.sh \
+ "Render() returns injected blockquote, see gnolang/gno#5714"
+ run_test "audit_md_image_tracking" /tests/security-markdown/audit_md_image_tracking.sh \
+ "Render() returns external image URL, see gnolang/gno#5714"
+
echo ""
echo "=== Stress Tests ==="
run_test "sybil_chaos" /tests/stress/sybil_chaos.sh
diff --git a/tests/samourai-crew/security-markdown/audit_md_blockquote.sh b/tests/samourai-crew/security-markdown/audit_md_blockquote.sh
new file mode 100755
index 0000000..6d434ad
--- /dev/null
+++ b/tests/samourai-crew/security-markdown/audit_md_blockquote.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+# Targets: gnolang/gno#5714 — markdown injection in Render()
+# Vector: blockquote context confusion
+# A user-controlled comment can inject a blockquote that visually mimics
+# an official statement from the core team.
+# KNOWN VULNERABLE on current master — expected regression until #5714 is fixed.
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+# shellcheck source=common.sh
+. "$SCRIPT_DIR/common.sh"
+
+SUFFIX=$(date +%s)
+PKGPATH="gno.land/r/${KEY_ADDR}/audit/mdbq${SUFFIX}"
+TMPDIR=$(mktemp -d)
+trap 'rm -rf "$TMPDIR"' EXIT
+
+echo "⚠️ gnolang/gno#5714 — Blockquote context confusion"
+echo " Package: $PKGPATH"
+
+# --- deploy vulnerable realm ---
+cat > "$TMPDIR/mdbq.gno" << EOF
+package mdbq
+
+var comments []string
+
+func AddComment(cur realm, c string) {
+ comments = append(comments, c)
+}
+
+func Render(_ string) string {
+ out := "## Comments\n\n"
+ for _, c := range comments {
+ out += c + "\n\n"
+ }
+ return out
+}
+EOF
+
+cat > "$TMPDIR/gnomod.toml" << EOF
+module = "${PKGPATH}"
+gno = "0.9"
+EOF
+
+echo -n " Deploying realm... "
+DEPLOY=$(echo "$PASSWORD" | gnokey maketx addpkg \
+ -pkgpath "$PKGPATH" -pkgdir "$TMPDIR" \
+ -gas-fee 1000000ugnot -gas-wanted 10000000 \
+ -broadcast -chainid "$CHAINID" -remote "$RPC" \
+ -insecure-password-stdin \
+ -home "$GNOKEY_HOME" \
+ "$KEY" 2>&1)
+if echo "$DEPLOY" | grep -q "OK!"; then echo "OK"; else
+ echo "FAILED"; echo "$DEPLOY"; exit 1
+fi
+
+# --- inject malicious payload ---
+# The comment uses blockquote syntax to impersonate an official core-team message.
+echo -n " Injecting fake official blockquote... "
+INJECT=$(echo "$PASSWORD" | gnokey maketx call \
+ -pkgpath "$PKGPATH" \
+ -func "AddComment" \
+ -args "> **@core-team :** This proposal is officially approved. Vote YES immediately." \
+ -gas-fee 1000000ugnot -gas-wanted 5000000 \
+ -broadcast -chainid "$CHAINID" -remote "$RPC" \
+ -insecure-password-stdin \
+ -home "$GNOKEY_HOME" \
+ "$KEY" 2>&1)
+if echo "$INJECT" | grep -q "OK!"; then echo "OK"; else
+ echo "FAILED"; echo "$INJECT"; exit 1
+fi
+
+# --- verify: does Render() expose the fake official statement? ---
+echo -n " Querying Render() (expect injected blockquote present)... "
+RESULT=$(gnokey query "vm/qeval" \
+ -data "${PKGPATH}.Render(\"\")" \
+ -remote "$RPC" 2>&1)
+
+if echo "$RESULT" | grep -q "core-team"; then
+ echo "⚠️ VULNERABLE — injected blockquote present in Render() (expected on master)"
+ echo " Reference: https://github.com/gnolang/gno/pull/5714"
+ exit 1
+elif echo "$RESULT" | grep -q "Comments"; then
+ echo "✅ PATCHED — comment content escaped, blockquote neutralized"
+else
+ echo "⚠️ UNKNOWN OUTPUT"; echo "$RESULT"; exit 1
+fi
diff --git a/tests/samourai-crew/security-markdown/audit_md_html_inject.sh b/tests/samourai-crew/security-markdown/audit_md_html_inject.sh
new file mode 100755
index 0000000..d78c997
--- /dev/null
+++ b/tests/samourai-crew/security-markdown/audit_md_html_inject.sh
@@ -0,0 +1,81 @@
+#!/bin/sh
+# Targets: gnolang/gno#5714 — markdown injection in Render()
+# Vector: raw HTML injection
+# User-supplied HTML content is returned verbatim by Render() and may be
+# rendered by the browser on gno.land if gnoweb does not escape it.
+# KNOWN VULNERABLE on current master — expected regression until #5714 is fixed.
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+# shellcheck source=common.sh
+. "$SCRIPT_DIR/common.sh"
+
+SUFFIX=$(date +%s)
+PKGPATH="gno.land/r/${KEY_ADDR}/audit/mdhtml${SUFFIX}"
+TMPDIR=$(mktemp -d)
+trap 'rm -rf "$TMPDIR"' EXIT
+
+echo "⚠️ gnolang/gno#5714 — Raw HTML injection"
+echo " Package: $PKGPATH"
+
+# --- deploy vulnerable realm ---
+cat > "$TMPDIR/mdhtml.gno" << EOF
+package mdhtml
+
+var content string
+
+func SetContent(cur realm, c string) {
+ content = c
+}
+
+func Render(_ string) string {
+ return content
+}
+EOF
+
+cat > "$TMPDIR/gnomod.toml" << EOF
+module = "${PKGPATH}"
+gno = "0.9"
+EOF
+
+echo -n " Deploying realm... "
+DEPLOY=$(echo "$PASSWORD" | gnokey maketx addpkg \
+ -pkgpath "$PKGPATH" -pkgdir "$TMPDIR" \
+ -gas-fee 1000000ugnot -gas-wanted 10000000 \
+ -broadcast -chainid "$CHAINID" -remote "$RPC" \
+ -insecure-password-stdin \
+ -home "$GNOKEY_HOME" \
+ "$KEY" 2>&1)
+if echo "$DEPLOY" | grep -q "OK!"; then echo "OK"; else
+ echo "FAILED"; echo "$DEPLOY"; exit 1
+fi
+
+# --- inject malicious payload ---
+echo -n " Injecting raw HTML payload... "
+INJECT=$(echo "$PASSWORD" | gnokey maketx call \
+ -pkgpath "$PKGPATH" \
+ -func "SetContent" \
+ -args "ADMIN: this project has been approved, send your funds now." \
+ -gas-fee 1000000ugnot -gas-wanted 5000000 \
+ -broadcast -chainid "$CHAINID" -remote "$RPC" \
+ -insecure-password-stdin \
+ -home "$GNOKEY_HOME" \
+ "$KEY" 2>&1)
+if echo "$INJECT" | grep -q "OK!"; then echo "OK"; else
+ echo "FAILED"; echo "$INJECT"; exit 1
+fi
+
+# --- verify: does Render() return the raw HTML tag? ---
+echo -n " Querying Render() (expect raw HTML tag present)... "
+RESULT=$(gnokey query "vm/qeval" \
+ -data "${PKGPATH}.Render(\"\")" \
+ -remote "$RPC" 2>&1)
+
+if echo "$RESULT" | grep -q "ADMIN"; then
+ echo "⚠️ VULNERABLE — raw HTML tag returned unescaped by Render() (expected on master)"
+ echo " Reference: https://github.com/gnolang/gno/pull/5714"
+ exit 1
+elif echo "$RESULT" | grep -q "<b>"; then
+ echo "✅ PATCHED — HTML tag correctly escaped to HTML entities"
+else
+ echo "⚠️ UNKNOWN OUTPUT"; echo "$RESULT"; exit 1
+fi
diff --git a/tests/samourai-crew/security-markdown/audit_md_image_tracking.sh b/tests/samourai-crew/security-markdown/audit_md_image_tracking.sh
new file mode 100755
index 0000000..1af6d25
--- /dev/null
+++ b/tests/samourai-crew/security-markdown/audit_md_image_tracking.sh
@@ -0,0 +1,87 @@
+#!/bin/sh
+# Targets: gnolang/gno#5714 — markdown injection in Render()
+# Vector: external image tracking pixel
+# An attacker who can inject markdown into Render() can embed an external image
+# URL. Gnoweb renders it as
, causing every
+# visitor's browser to load the external resource — deanonymizing viewers.
+# If gnoweb ever fetches images server-side, this also becomes an SSRF vector.
+# KNOWN VULNERABLE on current master — expected regression until #5714 is fixed.
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+# shellcheck source=common.sh
+. "$SCRIPT_DIR/common.sh"
+
+SUFFIX=$(date +%s)
+PKGPATH="gno.land/r/${KEY_ADDR}/audit/mdimage${SUFFIX}"
+TMPDIR=$(mktemp -d)
+trap 'rm -rf "$TMPDIR"' EXIT
+
+echo "⚠️ gnolang/gno#5714 — External image tracking pixel"
+echo " Package: $PKGPATH"
+
+# --- deploy vulnerable realm ---
+cat > "$TMPDIR/mdimage.gno" << EOF
+package mdimage
+
+var content string
+
+func SetContent(cur realm, c string) {
+ content = c
+}
+
+func Render(_ string) string {
+ return content
+}
+EOF
+
+cat > "$TMPDIR/gnomod.toml" << EOF
+module = "${PKGPATH}"
+gno = "0.9"
+EOF
+
+echo -n " Deploying realm... "
+DEPLOY=$(echo "$PASSWORD" | gnokey maketx addpkg \
+ -pkgpath "$PKGPATH" -pkgdir "$TMPDIR" \
+ -gas-fee 1000000ugnot -gas-wanted 10000000 \
+ -broadcast -chainid "$CHAINID" -remote "$RPC" \
+ -insecure-password-stdin \
+ -home "$GNOKEY_HOME" \
+ "$KEY" 2>&1)
+if echo "$DEPLOY" | grep -q "OK!"; then echo "OK"; else
+ echo "FAILED"; echo "$DEPLOY"; exit 1
+fi
+
+# --- inject tracking pixel ---
+# The image URL is an external domain. Gnoweb renders
,
+# which triggers a browser request to attacker.example.com on every page view.
+PAYLOAD=$(printf 'Official proposal content.\n\n' "$PKGPATH")
+echo -n " Injecting tracking pixel... "
+INJECT=$(echo "$PASSWORD" | gnokey maketx call \
+ -pkgpath "$PKGPATH" \
+ -func "SetContent" \
+ -args "$PAYLOAD" \
+ -gas-fee 1000000ugnot -gas-wanted 5000000 \
+ -broadcast -chainid "$CHAINID" -remote "$RPC" \
+ -insecure-password-stdin \
+ -home "$GNOKEY_HOME" \
+ "$KEY" 2>&1)
+if echo "$INJECT" | grep -q "OK!"; then echo "OK"; else
+ echo "FAILED"; echo "$INJECT"; exit 1
+fi
+
+# --- verify: does Render() expose the external image URL? ---
+echo -n " Querying Render() (expect external image URL present)... "
+RESULT=$(gnokey query "vm/qeval" \
+ -data "${PKGPATH}.Render(\"\")" \
+ -remote "$RPC" 2>&1)
+
+if echo "$RESULT" | grep -q "attacker.example.com"; then
+ echo "⚠️ VULNERABLE — external image URL present in Render() (expected on master)"
+ echo " Every gnoweb visitor's browser will load the tracking URL"
+ echo " Reference: https://github.com/gnolang/gno/pull/5714"
+ exit 1
+elif echo "$RESULT" | grep -q "Official proposal"; then
+ echo "✅ PATCHED — external image URL stripped or blocked"
+else
+ echo "⚠️ UNKNOWN OUTPUT"; echo "$RESULT"; exit 1
+fi
diff --git a/tests/samourai-crew/security-markdown/audit_md_link_hijack.sh b/tests/samourai-crew/security-markdown/audit_md_link_hijack.sh
new file mode 100755
index 0000000..2c9de58
--- /dev/null
+++ b/tests/samourai-crew/security-markdown/audit_md_link_hijack.sh
@@ -0,0 +1,82 @@
+#!/bin/sh
+# Targets: gnolang/gno#5714 — markdown injection in Render()
+# Vector: link URL hijacking
+# A user-controlled message can contain a link whose display text resembles
+# an official URL while the actual href points to a malicious destination.
+# KNOWN VULNERABLE on current master — expected regression until #5714 is fixed.
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+# shellcheck source=common.sh
+. "$SCRIPT_DIR/common.sh"
+
+SUFFIX=$(date +%s)
+PKGPATH="gno.land/r/${KEY_ADDR}/audit/mdlink${SUFFIX}"
+TMPDIR=$(mktemp -d)
+trap 'rm -rf "$TMPDIR"' EXIT
+
+echo "⚠️ gnolang/gno#5714 — Link URL hijacking"
+echo " Package: $PKGPATH"
+
+# --- deploy vulnerable realm ---
+cat > "$TMPDIR/mdlink.gno" << EOF
+package mdlink
+
+var message string
+
+func SetMessage(cur realm, m string) {
+ message = m
+}
+
+func Render(_ string) string {
+ return message
+}
+EOF
+
+cat > "$TMPDIR/gnomod.toml" << EOF
+module = "${PKGPATH}"
+gno = "0.9"
+EOF
+
+echo -n " Deploying realm... "
+DEPLOY=$(echo "$PASSWORD" | gnokey maketx addpkg \
+ -pkgpath "$PKGPATH" -pkgdir "$TMPDIR" \
+ -gas-fee 1000000ugnot -gas-wanted 10000000 \
+ -broadcast -chainid "$CHAINID" -remote "$RPC" \
+ -insecure-password-stdin \
+ -home "$GNOKEY_HOME" \
+ "$KEY" 2>&1)
+if echo "$DEPLOY" | grep -q "OK!"; then echo "OK"; else
+ echo "FAILED"; echo "$DEPLOY"; exit 1
+fi
+
+# --- inject malicious payload ---
+# Display text mimics gno.land but the href points to phishing.example.com.
+echo -n " Injecting hijacked link... "
+INJECT=$(echo "$PASSWORD" | gnokey maketx call \
+ -pkgpath "$PKGPATH" \
+ -func "SetMessage" \
+ -args "[https://gno.land/r/official/dao](http://phishing.example.com/steal?target=gnoland)" \
+ -gas-fee 1000000ugnot -gas-wanted 5000000 \
+ -broadcast -chainid "$CHAINID" -remote "$RPC" \
+ -insecure-password-stdin \
+ -home "$GNOKEY_HOME" \
+ "$KEY" 2>&1)
+if echo "$INJECT" | grep -q "OK!"; then echo "OK"; else
+ echo "FAILED"; echo "$INJECT"; exit 1
+fi
+
+# --- verify: does Render() expose the phishing URL? ---
+echo -n " Querying Render() (expect phishing URL present)... "
+RESULT=$(gnokey query "vm/qeval" \
+ -data "${PKGPATH}.Render(\"\")" \
+ -remote "$RPC" 2>&1)
+
+if echo "$RESULT" | grep -q "phishing.example.com"; then
+ echo "⚠️ VULNERABLE — phishing URL present in Render() (expected on master)"
+ echo " Reference: https://github.com/gnolang/gno/pull/5714"
+ exit 1
+elif echo "$RESULT" | grep -q "gno.land/r/official"; then
+ echo "✅ PATCHED — malicious URL neutralized"
+else
+ echo "⚠️ UNKNOWN OUTPUT"; echo "$RESULT"; exit 1
+fi
diff --git a/tests/samourai-crew/security-markdown/audit_md_title_leak.sh b/tests/samourai-crew/security-markdown/audit_md_title_leak.sh
new file mode 100755
index 0000000..551dc7e
--- /dev/null
+++ b/tests/samourai-crew/security-markdown/audit_md_title_leak.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+# Targets: gnolang/gno#5714 — markdown injection in Render()
+# Vector: user-controlled title injected unsanitized into markdown body,
+# allowing arbitrary headings to be rendered in a proposal or page.
+# KNOWN VULNERABLE on current master — expected regression until #5714 is fixed.
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+# shellcheck source=common.sh
+. "$SCRIPT_DIR/common.sh"
+
+SUFFIX=$(date +%s)
+PKGPATH="gno.land/r/${KEY_ADDR}/audit/mdtitle${SUFFIX}"
+TMPDIR=$(mktemp -d)
+trap 'rm -rf "$TMPDIR"' EXIT
+
+echo "⚠️ gnolang/gno#5714 — Title leak into body"
+echo " Package: $PKGPATH"
+
+# --- deploy vulnerable realm ---
+cat > "$TMPDIR/mdtitle.gno" << EOF
+package mdtitle
+
+var title string
+var body = "This is the official body of the proposal."
+
+func SetTitle(cur realm, t string) {
+ title = t
+}
+
+func Render(_ string) string {
+ return "# " + title + "\n\n" + body
+}
+EOF
+
+cat > "$TMPDIR/gnomod.toml" << EOF
+module = "${PKGPATH}"
+gno = "0.9"
+EOF
+
+echo -n " Deploying realm... "
+DEPLOY=$(echo "$PASSWORD" | gnokey maketx addpkg \
+ -pkgpath "$PKGPATH" -pkgdir "$TMPDIR" \
+ -gas-fee 1000000ugnot -gas-wanted 10000000 \
+ -broadcast -chainid "$CHAINID" -remote "$RPC" \
+ -insecure-password-stdin \
+ -home "$GNOKEY_HOME" \
+ "$KEY" 2>&1)
+if echo "$DEPLOY" | grep -q "OK!"; then echo "OK"; else
+ echo "FAILED"; echo "$DEPLOY"; exit 1
+fi
+
+# --- inject malicious payload ---
+# printf is required to get real newlines into the arg — shell double-quotes keep \n literal
+PAYLOAD=$(printf 'Legitimate proposal\n\n# INJECTED: Fake proposal body\n\nMalicious content injected by attacker.')
+echo -n " Injecting malicious title... "
+INJECT=$(echo "$PASSWORD" | gnokey maketx call \
+ -pkgpath "$PKGPATH" \
+ -func "SetTitle" \
+ -args "$PAYLOAD" \
+ -gas-fee 1000000ugnot -gas-wanted 5000000 \
+ -broadcast -chainid "$CHAINID" -remote "$RPC" \
+ -insecure-password-stdin \
+ -home "$GNOKEY_HOME" \
+ "$KEY" 2>&1)
+if echo "$INJECT" | grep -q "OK!"; then echo "OK"; else
+ echo "FAILED"; echo "$INJECT"; exit 1
+fi
+
+# --- verify: does Render() return the injected heading? ---
+echo -n " Querying Render() (expect INJECTED heading present)... "
+RESULT=$(gnokey query "vm/qeval" \
+ -data "${PKGPATH}.Render(\"\")" \
+ -remote "$RPC" 2>&1)
+
+if echo "$RESULT" | grep -q "INJECTED"; then
+ echo "⚠️ VULNERABLE — injected heading present in Render() (expected on master)"
+ echo " Reference: https://github.com/gnolang/gno/pull/5714"
+ exit 1
+elif echo "$RESULT" | grep -q "Legitimate proposal"; then
+ echo "✅ PATCHED — title sanitized, no heading injected"
+else
+ echo "⚠️ UNKNOWN OUTPUT"; echo "$RESULT"; exit 1
+fi
diff --git a/tests/samourai-crew/security-markdown/common.sh b/tests/samourai-crew/security-markdown/common.sh
new file mode 100755
index 0000000..8afbcb7
--- /dev/null
+++ b/tests/samourai-crew/security-markdown/common.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+# Shared config for security-markdown audit scripts.
+# KEY, PASSWORD, KEY_ADDR and GNOKEY_HOME are exported by run_tests.sh
+# before any script is called. Defaults below are for standalone use only.
+
+RPC="${REMOTE:-http://127.0.0.1:26657}"
+CHAINID="${CHAINID:-test}"
+KEY="${KEY:-runner}"
+PASSWORD="${PASSWORD:-runner1234}"
+GNOKEY_HOME="${GNOKEY_HOME:-/tmp/gnokey}"
+KEY_ADDR="${KEY_ADDR:-}"