Summary
serveDebug() registers Go's standard net/http/pprof endpoints,
including /debug/pprof/heap and /debug/pprof/goroutine, directly on the
same gin engine that serves the main API, with no authentication
middleware of any kind. This is guarded by a single check,
if "prod" == util.Mode { return }, so it is disabled by default in
release builds. However, util.Mode is set by a documented, user-facing
CLI flag on the serve command, --mode, whose help text reads simply
"dev/prod" with no indication that the non-default value exposes raw
process memory to the network with zero authentication. A heap or
goroutine dump of a running SiYuan kernel can contain the workspace's
AccessAuthCode and any configured AI provider API keys, all stored as
plain Go strings in the in-memory Conf structure, alongside arbitrary
note content and other session state. This is CWE-215 (Information
Exposure Through Debug Information) and CWE-497 (Exposure of Sensitive
System Information to an Unauthorized Control Sphere), with CWE-400
(Uncontrolled Resource Consumption) as a secondary concern via
/debug/pprof/profile//debug/pprof/trace, which can be made to
block/consume CPU for an attacker-chosen duration.
Details
kernel/server/serve.go, serveDebug():
func serveDebug(ginServer *gin.Engine) {
if "prod" == util.Mode {
// The production environment will no longer register `/debug/pprof/` https://github.com/siyuan-note/siyuan/issues/10152
return
}
ginServer.GET("/debug/pprof/", gin.WrapF(pprof.Index))
ginServer.GET("/debug/pprof/allocs", gin.WrapF(pprof.Index))
ginServer.GET("/debug/pprof/block", gin.WrapF(pprof.Index))
ginServer.GET("/debug/pprof/goroutine", gin.WrapF(pprof.Index))
ginServer.GET("/debug/pprof/heap", gin.WrapF(pprof.Index))
ginServer.GET("/debug/pprof/mutex", gin.WrapF(pprof.Index))
ginServer.GET("/debug/pprof/threadcreate", gin.WrapF(pprof.Index))
ginServer.GET("/debug/pprof/cmdline", gin.WrapF(pprof.Cmdline))
ginServer.GET("/debug/pprof/profile", gin.WrapF(pprof.Profile))
ginServer.GET("/debug/pprof/symbol", gin.WrapF(pprof.Symbol))
ginServer.GET("/debug/pprof/trace", gin.WrapF(pprof.Trace))
}
None of these routes pass model.CheckAuth or any other middleware, unlike
every API route in the application.
util.Mode (kernel/util/working.go:45) defaults to "prod"
(var Mode = "prod"), and the referenced issue #10152 shows the
maintainers already fixed the "always registered" version of this bug
once. The remaining exposure is entirely through the documented --mode
flag on the serve CLI command (kernel/cli/cmd/serve.go:106):
serveCmd.Flags().StringVar(&serveMode, "mode", "prod", "dev/prod")
This is ordinary, discoverable CLI surface (kernel serve --help shows
it), not a hidden debug backdoor, and nothing in its help text or
documentation conveys that choosing dev disables authentication on a
process-memory-dumping endpoint. This is exactly the kind of flag an
operator might reasonably pass while troubleshooting a self-hosted
instance, including a network-exposed one, without realizing the security
implication. The check itself is also a strict-equality allowlist of one
string ("prod"); any other value, including a future additional mode,
a typo, or "production" instead of "prod", silently falls through to
registering these routes.
Secrets confirmed present as plain in-memory strings and therefore
recoverable from a heap dump:
Conf.AccessAuthCode (the workspace lock-screen code covered elsewhere
in this review)
kernel/conf/ai.go: multiple APIKey string fields across AI provider
configuration structs
PoC
# Start SiYuan with the documented dev flag, e.g.:
# kernel serve --mode dev --workspace <path>
# Then, with no credentials of any kind:
curl -s http://<target>:6806/debug/pprof/heap -o heap.out
curl -s http://<target>:6806/debug/pprof/goroutine?debug=2
curl -s http://<target>:6806/debug/pprof/cmdline
# heap.out can be searched/analyzed offline (e.g. with `go tool pprof` or
# simple string extraction) for API keys, the access code, and note
# content residing in memory at dump time.
# Resource-exhaustion angle, no special flags needed once exposed:
curl -s "http://<target>:6806/debug/pprof/profile?seconds=60" &
# repeat concurrently to tie up CPU/goroutines for the requested duration
(Not run against a live compiled kernel, same sandbox limitation as prior
findings in this round; the routing/guard logic and the CLI flag default
are read directly from the three locations quoted above, and
net/http/pprof's content, full heap/goroutine memory dumps with no
redaction, is standard, well-documented Go standard library behavior.)
Impact
Any SiYuan deployment started with --mode dev (or any value other than
exactly "prod") on a network-reachable interface exposes complete,
unauthenticated memory-dump and CPU-profiling endpoints. A single request
to /debug/pprof/heap can recover the workspace's AccessAuthCode
(defeating every other authentication control examined in this review) and
any configured AI provider API keys, with no session, cookie, or
credential required at all. This is a well-known, frequently-exploited
real-world vulnerability class for Go services in general; the specific
concern here is that SiYuan exposes it through a documented, easily-typed
CLI flag with no warning that "dev mode" carries this consequence, making
accidental exposure during routine troubleshooting plausible even for
operators who are otherwise careful about the application's other
authentication settings.
## Affected products
| Field | Value |
|---|---|
| Ecosystem | **Go** |
| Package name | `github.com/siyuan-note/siyuan/kernel` |
| Affected versions | `<= 3.7.3` (confirmed present in 3.7.3; conditional on `--mode` not equal to `"prod"`, which is not the default) |
| Patched versions | *(none yet, leave blank until a fix is released)* |
## Severity
| Field | Value |
|---|---|
| Vector string | `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:L` |
| Score | **9.1 (Critical)** *if* the non-default `--mode` value is in effect (network vector, no privileges or interaction needed, scope change since recovered secrets grant access far beyond this endpoint itself, high confidentiality impact, some availability impact via the profiling endpoints). Given this requires a non-default runtime flag, maintainers may reasonably prefer scoring this as environmental/conditional rather than a flat 9.1; recommend presenting both the "if triggered" severity and the precondition clearly in the advisory, exactly as done here, rather than picking one number that misrepresents either the ceiling or the default-safe floor. |
## Weaknesses (CWE)
- **CWE-215**: Information Exposure Through Debug Information (primary)
- **CWE-497**: Exposure of Sensitive System Information to an Unauthorized Control Sphere
- **CWE-400**: Uncontrolled Resource Consumption (via `/debug/pprof/profile` and `/debug/pprof/trace`)
## Notes for filing
- Genuinely distinct root cause from the `/public/` authentication
advisory (different code path, different trigger condition, different
consequence, direct secret disclosure vs. content disclosure), safe to
file separately, though both share the broader theme from this review of
routes that fall outside the application's otherwise-consistent
`CheckAuth` enforcement.
- Suggested fix direction: at minimum, update the `--mode` flag's help
text and documentation to explicitly warn that `dev` mode exposes
unauthenticated process-memory-dump endpoints and should never be used
on a network-reachable instance. More robustly, gate `serveDebug()`
behind its own explicit opt-in flag (e.g. `--enable-pprof`) separate
from the general dev/prod mode, and/or require `model.CheckAuth` +
`model.CheckAdminRole` on these routes the same as every other
sensitive endpoint in the application, rather than relying solely on a
string-equality check against one deployment mode.
Summary
serveDebug()registers Go's standardnet/http/pprofendpoints,including
/debug/pprof/heapand/debug/pprof/goroutine, directly on thesame gin engine that serves the main API, with no authentication
middleware of any kind. This is guarded by a single check,
if "prod" == util.Mode { return }, so it is disabled by default inrelease builds. However,
util.Modeis set by a documented, user-facingCLI flag on the
servecommand,--mode, whose help text reads simply"dev/prod"with no indication that the non-default value exposes rawprocess memory to the network with zero authentication. A heap or
goroutine dump of a running SiYuan kernel can contain the workspace's
AccessAuthCodeand any configured AI provider API keys, all stored asplain Go strings in the in-memory
Confstructure, alongside arbitrarynote content and other session state. This is CWE-215 (Information
Exposure Through Debug Information) and CWE-497 (Exposure of Sensitive
System Information to an Unauthorized Control Sphere), with CWE-400
(Uncontrolled Resource Consumption) as a secondary concern via
/debug/pprof/profile//debug/pprof/trace, which can be made toblock/consume CPU for an attacker-chosen duration.
Details
kernel/server/serve.go,serveDebug():None of these routes pass
model.CheckAuthor any other middleware, unlikeevery API route in the application.
util.Mode(kernel/util/working.go:45) defaults to"prod"(
var Mode = "prod"), and the referenced issue #10152 shows themaintainers already fixed the "always registered" version of this bug
once. The remaining exposure is entirely through the documented
--modeflag on the
serveCLI command (kernel/cli/cmd/serve.go:106):This is ordinary, discoverable CLI surface (
kernel serve --helpshowsit), not a hidden debug backdoor, and nothing in its help text or
documentation conveys that choosing
devdisables authentication on aprocess-memory-dumping endpoint. This is exactly the kind of flag an
operator might reasonably pass while troubleshooting a self-hosted
instance, including a network-exposed one, without realizing the security
implication. The check itself is also a strict-equality allowlist of one
string (
"prod"); any other value, including a future additional mode,a typo, or
"production"instead of"prod", silently falls through toregistering these routes.
Secrets confirmed present as plain in-memory strings and therefore
recoverable from a heap dump:
Conf.AccessAuthCode(the workspace lock-screen code covered elsewherein this review)
kernel/conf/ai.go: multipleAPIKey stringfields across AI providerconfiguration structs
PoC
(Not run against a live compiled kernel, same sandbox limitation as prior
findings in this round; the routing/guard logic and the CLI flag default
are read directly from the three locations quoted above, and
net/http/pprof's content, full heap/goroutine memory dumps with noredaction, is standard, well-documented Go standard library behavior.)
Impact
Any SiYuan deployment started with
--mode dev(or any value other thanexactly
"prod") on a network-reachable interface exposes complete,unauthenticated memory-dump and CPU-profiling endpoints. A single request
to
/debug/pprof/heapcan recover the workspace'sAccessAuthCode(defeating every other authentication control examined in this review) and
any configured AI provider API keys, with no session, cookie, or
credential required at all. This is a well-known, frequently-exploited
real-world vulnerability class for Go services in general; the specific
concern here is that SiYuan exposes it through a documented, easily-typed
CLI flag with no warning that "dev mode" carries this consequence, making
accidental exposure during routine troubleshooting plausible even for
operators who are otherwise careful about the application's other
authentication settings.