Executive summary
This report consolidates a single, prioritized security issue found in the samples/tokens sample stack: a dangerous default configuration that combines services bound to 0.0.0.0, TLS disabled in sample configs, an originally permissive CORS middleware (allowed any origin and exposed Authorization), and an exposed Swagger UI in docker-compose. Together these create a high-severity risk for accidental exposure when developers run samples on public or not-isolated environments.
- Developers often run samples with defaults. Defaulting to insecure choices (0.0.0.0, TLS disabled, permissive CORS, public Swagger UI) amplifies risk: any misconfiguration or public hosting can expose privileged APIs or state.
- The impact is broad for this project: these samples demonstrate how to run services and may be copied into deployments or used in demos without adequate hardening.
Files of interest (evidence)
samples/tokens/owner/main.go, samples/tokens/issuer/main.go, samples/tokens/endorser/main.go — services bind to 0.0.0.0
samples/tokens/conf/*/core.yaml — tls: enabled: false
samples/tokens/compose.yml — publishes swagger-ui (port 8080) and mounts swagger.yaml
samples/tokens/common/fsc.go — (original) permissive CORS middleware; replaced in repo with a conservative middleware
Key vulnerable snippets (original state)
- Service binding to all interfaces (example from mains):
// in samples/tokens/owner/main.go (and others)
s := &http.Server{
Handler: h,
Addr: net.JoinHostPort("0.0.0.0", *port),
}
go s.ListenAndServe()
- Sample TLS disabled (example):
# samples/tokens/conf/owner1/core.yaml
fabric:
default:
tls:
enabled: false
- Docker compose exposes Swagger UI (public by default):
swagger-ui:
image: swaggerapi/swagger-ui
ports:
- "8080:8080"
environment:
- URL=/swagger.yaml
volumes:
- ./swagger.yaml:/usr/share/nginx/html/swagger.yaml
- Original permissive CORS middleware (reconstructed):
// WithAnyCORS adds permissive CORS headers to all responses
func WithAnyCORS(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusNoContent)
return
}
next.ServeHTTP(w, r)
})
}
0.0.0.0 makes services reachable from network interfaces (including public IPs). If Docker host or VM is public, services are reachable externally.
- TLS disabled exposes traffic, credentials, or application-specific secrets in cleartext.
- Permissive CORS plus
Authorization in allowed headers means an attacker-controlled page can, from a browser, make authenticated cross-origin requests if user agent stores credentials or on shared machines.
- Swagger UI documents the API and is often used by developers to explore endpoints — exposing it publicly aids reconnaissance and lowers attacker effort.
Automated check (included)
A small test script was added to assert the conservative default (the fix) rejects unknown origins. Path: tests/check_cors_default.sh.
tests/check_cors_default.sh contents:
#!/usr/bin/env bash
set -euo pipefail
HOST=${1:-localhost:9300}
URL="http://${HOST}/endorser/init"
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X OPTIONS "$URL" -H "Origin: http://evil.example" -H "Access-Control-Request-Method: POST" || true)
if [ "$STATUS" == "403" ]; then
echo "PASS: preflight rejected (403)"
exit 0
else
echo "FAIL: preflight returned $STATUS"
exit 2
fi
Expected: With the conservative fix present in this tree (i.e., ALLOWED_ORIGINS not set), the test should pass (preflight returns 403). If ALLOWED_ORIGINS is set to include the origin, preflight will succeed and you'll need to test differently.
- Replaced permissive
WithAnyCORS middleware with a conservative WithCORS middleware that:
- Rejects cross-origin requests by default when
ALLOWED_ORIGINS is not configured.
- Accepts only explicitly configured origins (comma-separated
ALLOWED_ORIGINS).
- Requires
ALLOW_AUTH_HEADER=true to return Authorization in Access-Control-Allow-Headers.
- Updated
owner, issuer, and endorser mains to use the new middleware.
Executive summary
This report consolidates a single, prioritized security issue found in the
samples/tokenssample stack: a dangerous default configuration that combines services bound to0.0.0.0, TLS disabled in sample configs, an originally permissive CORS middleware (allowed any origin and exposedAuthorization), and an exposed Swagger UI indocker-compose. Together these create a high-severity risk for accidental exposure when developers run samples on public or not-isolated environments.Files of interest (evidence)
samples/tokens/owner/main.go,samples/tokens/issuer/main.go,samples/tokens/endorser/main.go— services bind to0.0.0.0samples/tokens/conf/*/core.yaml—tls: enabled: falsesamples/tokens/compose.yml— publishesswagger-ui(port 8080) and mountsswagger.yamlsamples/tokens/common/fsc.go— (original) permissive CORS middleware; replaced in repo with a conservative middlewareKey vulnerable snippets (original state)
0.0.0.0makes services reachable from network interfaces (including public IPs). If Docker host or VM is public, services are reachable externally.Authorizationin allowed headers means an attacker-controlled page can, from a browser, make authenticated cross-origin requests if user agent stores credentials or on shared machines.Automated check (included)
A small test script was added to assert the conservative default (the fix) rejects unknown origins. Path:
tests/check_cors_default.sh.tests/check_cors_default.shcontents:Expected: With the conservative fix present in this tree (i.e.,
ALLOWED_ORIGINSnot set), the test should pass (preflight returns403). IfALLOWED_ORIGINSis set to include the origin, preflight will succeed and you'll need to test differently.WithAnyCORSmiddleware with a conservativeWithCORSmiddleware that:ALLOWED_ORIGINSis not configured.ALLOWED_ORIGINS).ALLOW_AUTH_HEADER=trueto returnAuthorizationinAccess-Control-Allow-Headers.owner,issuer, andendorsermains to use the new middleware.