Security: Admin DAPI unauthenticated — GET /admin/v1/config leaks worker_private key #1471
Summary
The decentralized-api admin server (/admin/v1/*) registers routes with only logging middleware — no authentication.
GET /admin/v1/config returns the unsanitized live config as JSON, including ml_node_key_config.worker_private.
Other unauthenticated endpoints include POST /admin/v1/tx/send, claim recovery, bridge block inject, node enable/disable.
Affected components
| Path | Role |
|---|---|
decentralized-api/internal/server/admin/server.go |
Routes + getConfig |
decentralized-api/apiconfig/config.go |
WorkerPrivateKey json:"worker_private" |
decentralized-api/main.go |
Listens :%port (all interfaces) |
deploy/join/docker-compose.yml |
Maps 127.0.0.1:9200:9200 (mitigation only at compose layer) |
Source
// getConfig returns the current configuration as JSON (unsanitized)
func (s *Server) getConfig(c echo.Context) error {
cfg := s.configManager.GetConfig()
return c.JSONPretty(200, cfg, " ")
}
type MLNodeKeyConfig struct {
WorkerPublicKey string `json:"worker_public"`
WorkerPrivateKey string `json:"worker_private"` // leaked via JSON
}
Note: KeyringPassword correctly uses json:"-"; worker private key does not.
Reproduce (if admin port reachable)
curl -sS "http://HOST:9200/admin/v1/config" | jq '.ml_node_key_config'
# No Authorization header required
Impact
If admin port is exposed (misconfigured publish / proxy / SG):
- Theft of worker private key
- Abuse of
tx/sendto broadcast host-signed txs - Operational control of nodes / bridge / claim recovery
Default compose binds loopback only, but the app does not fail-closed to localhost.
Suggested remediation
- Require auth on all
/admin/v1/*(mTLS, bearer, or Unix socket only) - Sanitize secrets from any config export API
- Bind admin to
127.0.0.1in application code - Message-type allowlist + auth on
tx/send
Disclosure
No production hosts attacked. Happy to move this to HackerOne if preferred over public issues.
💬 Comments (1)
🔄 Auto-synced from Issue #1471 every hour.
Closing to focus disclosure on the highest-priority finding: https://github.com/gonka-ai/gonka/issues/1470 (SSRF via InferenceUrl). Other items can be re-opened or filed via HackerOne if needed.