CVE-2026-79667
Ech0 before 4.4.3 Authentication Bypass via Scope Enforcement
Ech0 version 4.3.4 and earlier fails to reliably enforce scoped access token (least-privilege) restrictions on several privileged admin routes. Multiple privileged endpoints (e.g., /api/inbox, /api/panel/comments, /api/backup/export) omit scope checks and authorize based only on the user's admin role, and the backup export handler discards token scope metadata entirely. An attacker holding a deliberately limited (low-scope) admin access token can reach broader privileged functionality than intended, including reading the inbox and exporting a full database backup ZIP archive. Fixed in 4.4.3.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- Low
- Availability
- Low
Exploit likelihood
What each source reports
CVE List Score used
7.2
Ech0 before 4.4.3 Authentication Bypass via Scope Enforcement
Ech0 version 4.3.4 and earlier fails to reliably enforce scoped access token (least-privilege) restrictions on several privileged admin routes. Multiple privileged endpoints (e.g., /api/inbox, /api/panel/comments, /api/backup/export) omit scope checks and authorize based only on the user's admin role, and the backup export handler discards token scope metadata entirely. An attacker holding a deliberately limited (low-scope) admin access token can reach broader privileged functionality than intended, including reading the inbox and exporting a full database backup ZIP archive. Fixed in 4.4.3.
- Record
CVE-2026-79667- CVSS 4.0
- 7.2 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:L/VA:L/SC:N/SI:N/SA:N - CVSS 3.1
- 7.6 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L - Weakness
- CWE-285
- Updated
- 2026-11-02
EUVDEUVD-2026-65447
7.2
Ech0 version 4.3.4 and earlier fails to reliably enforce scoped access token (least-privilege) restrictions on several privileged admin routes. Multiple privileged endpoints (e.g., /api/inbox, /api/panel/comments, /api/backup/export) omit scope checks and authorize based only on the user's admin role, and the backup export handler discards token scope metadata entirely. An attacker holding a deliberately limited (low-scope) admin access token can reach broader privileged functionality than intended, including reading the inbox and exporting a full database backup ZIP archive. Fixed in 4.4.3.
- Record
EUVD-2026-65447- CVSS 4.0
- 7.2 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:L/VA:L/SC:N/SI:N/SA:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-4h9q-p5j4-xvvh
7.6
Ech0: Scoped admin access tokens can bypass least-privilege controls on privileged endpoints, including backup export
Summary
Ech0 scoped access tokens do not reliably enforce least privilege: multiple privileged admin routes omit scope checks, and the backup export handler strips token scope metadata entirely, allowing a low-scope admin access token to reach broader admin functionality than intended.
Impact
An attacker who obtains a deliberately limited access token for an admin account can use that token to access privileged functionality outside its assigned scope. Confirmed impact includes access to /api/inbox with a token scoped only for echo:read and successful backup export via /api/backup/export?token=..., which returns a full ZIP archive. In practice, this turns a narrowly delegated API token into a broader privileged access and data exfiltration primitive.
Details
The issue is caused by a split authorization model:
JWTAuthMiddleware()authenticates the token and stores scope metadata in the viewer contextRequireScopes(...)enforces least privilege, but only when a route explicitly adds it- several privileged routes omit
RequireScopes(...) - multiple service methods then authorize using only
user.IsAdmin
internal/middleware/scope.go shows that scope enforcement is opt-in:
func RequireScopes(scopes ...string) gin.HandlerFunc {
return func(ctx *gin.Context) {
v := viewer.MustFromContext(ctx.Request.Context())
if v.TokenType() == authModel.TokenTypeSession {
ctx.Next()
return
}
if v.TokenType() != authModel.TokenTypeAccess { ... }
if !containsValidAudience(v.Audience()) { ... }
if !containsAllScopes(v.Scopes(), scopes) { ... }
ctx.Next()
}
}
Representative privileged routes omit RequireScopes(...), for example internal/router/inbox.go:
func setupInboxRoutes(appRouterGroup *AppRouterGroup, h *handler.Bundle) {
appRouterGroup.AuthRouterGroup.GET("/inbox", h.InboxHandler.GetInboxList())
appRouterGroup.AuthRouterGroup.GET("/inbox/unread", h.InboxHandler.GetUnreadInbox())
appRouterGroup.AuthRouterGroup.PUT("/inbox/:id/read", h.InboxHandler.MarkInboxAsRead())
appRouterGroup.AuthRouterGroup.DELETE("/inbox/:id", h.InboxHandler.DeleteInbox())
appRouterGroup.AuthRouterGroup.DELETE("/inbox", h.InboxHandler.ClearInbox())
}
Other source-confirmed unguarded privileged surfaces include:
/api/panel/comments*/api/addConnect/api/delConnect/:id/api/migration/*/api/backup/export
Service-layer authorization often checks only admin role. For example, internal/service/inbox/inbox.go:
func (inboxService *InboxService) ensureAdmin(ctx context.Context) error {
userid := viewer.MustFromContext(ctx).UserID()
user, err := inboxService.commonService.CommonGetUserByUserId(ctx, userid)
if err != nil {
return err
}
if !user.IsAdmin {
return errors.New(commonModel.NO_PERMISSION_DENIED)
}
return nil
}
The backup export path is a stronger variant because it discards token metadata before authorization. internal/handler/backup/backup.go reparses a query token and rebuilds a bare viewer from only the user ID:
func (backupHandler *BackupHandler) ExportBackup() gin.HandlerFunc {
return res.Execute(func(ctx *gin.Context) res.Response {
token := ctx.Query("token")
claims, err := jwtUtil.ParseToken(token)
if err != nil { ... }
reqCtx := viewer.WithContext(context.Background(), viewer.NewUserViewer(claims.Userid))
if err := backupHandler.backupService.ExportBackup(ctx, reqCtx); err != nil { ... }
return res.Response{Msg: commonModel.EXPORT_BACKUP_SUCCESS}
})
}
This drops token type, scopes, audience, and token ID before the backup service runs.
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
curl -sS -X POST "http://127.0.0.1:6277/api/init/owner" \
-H 'Content-Type: application/json' \
-d…
- Record
GHSA-4h9q-p5j4-xvvh- CVSS 3.1
- 7.6 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L - Weakness
- CWE-285
- Updated
- 2026-11-02
GitHub AdvisoriesGHSA-vgpj-v99m-7h5j
7.2
Ech0 version 4.3.4 and earlier fails to reliably enforce scoped access token (least-privilege)...
Ech0 version 4.3.4 and earlier fails to reliably enforce scoped access token (least-privilege) restrictions on several privileged admin routes. Multiple privileged endpoints (e.g., /api/inbox, /api/panel/comments, /api/backup/export) omit scope checks and authorize based only on the user's admin role, and the backup export handler discards token scope metadata entirely. An attacker holding a deliberately limited (low-scope) admin access token can reach broader privileged functionality than intended, including reading the inbox and exporting a full database backup ZIP archive. Fixed in 4.4.3.
- Record
GHSA-vgpj-v99m-7h5j- CVSS 4.0
- 7.2 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:L/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 7.6 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L - Weakness
- CWE-285
- Updated
- 2026-11-02
NVD
7.2
Ech0 version 4.3.4 and earlier fails to reliably enforce scoped access token (least-privilege) restrictions on several privileged admin routes. Multiple privileged endpoints (e.g., /api/inbox, /api/panel/comments, /api/backup/export) omit scope checks and authorize based only on the user's admin role, and the backup export handler discards token scope metadata entirely. An attacker holding a deliberately limited (low-scope) admin access token can reach broader privileged functionality than intended, including reading the inbox and exporting a full database backup ZIP archive. Fixed in 4.4.3.
- Record
CVE-2026-79667- CVSS 4.0
- 7.2 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:L/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 7.6 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L - Weakness
- CWE-285
- Updated
- 2026-11-02
OSV
7.2
Ech0 before 4.4.3 Authentication Bypass via Scope Enforcement
Ech0 version 4.3.4 and earlier fails to reliably enforce scoped access token (least-privilege) restrictions on several privileged admin routes. Multiple privileged endpoints (e.g., /api/inbox, /api/panel/comments, /api/backup/export) omit scope checks and authorize based only on the user's admin role, and the backup export handler discards token scope metadata entirely. An attacker holding a deliberately limited (low-scope) admin access token can reach broader privileged functionality than intended, including reading the inbox and exporting a full database backup ZIP archive. Fixed in 4.4.3.
- Record
CVE-2026-79667- CVSS 4.0
- 7.2 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:L/VA:L/SC:N/SI:N/SA:N - Weakness
- CWE-285
- Updated
- 2026-11-02
OSVGHSA-4h9q-p5j4-xvvh
7.6
Ech0: Scoped admin access tokens can bypass least-privilege controls on privileged endpoints, including backup export
Summary
Ech0 scoped access tokens do not reliably enforce least privilege: multiple privileged admin routes omit scope checks, and the backup export handler strips token scope metadata entirely, allowing a low-scope admin access token to reach broader admin functionality than intended.
Impact
An attacker who obtains a deliberately limited access token for an admin account can use that token to access privileged functionality outside its assigned scope. Confirmed impact includes access to /api/inbox with a token scoped only for echo:read and successful backup export via /api/backup/export?token=..., which returns a full ZIP archive. In practice, this turns a narrowly delegated API token into a broader privileged access and data exfiltration primitive.
Details
The issue is caused by a split authorization model:
JWTAuthMiddleware()authenticates the token and stores scope metadata in the viewer contextRequireScopes(...)enforces least privilege, but only when a route explicitly adds it- several privileged routes omit
RequireScopes(...) - multiple service methods then authorize using only
user.IsAdmin
internal/middleware/scope.go shows that scope enforcement is opt-in:
func RequireScopes(scopes ...string) gin.HandlerFunc {
return func(ctx *gin.Context) {
v := viewer.MustFromContext(ctx.Request.Context())
if v.TokenType() == authModel.TokenTypeSession {
ctx.Next()
return
}
if v.TokenType() != authModel.TokenTypeAccess { ... }
if !containsValidAudience(v.Audience()) { ... }
if !containsAllScopes(v.Scopes(), scopes) { ... }
ctx.Next()
}
}
Representative privileged routes omit RequireScopes(...), for example internal/router/inbox.go:
func setupInboxRoutes(appRouterGroup *AppRouterGroup, h *handler.Bundle) {
appRouterGroup.AuthRouterGroup.GET("/inbox", h.InboxHandler.GetInboxList())
appRouterGroup.AuthRouterGroup.GET("/inbox/unread", h.InboxHandler.GetUnreadInbox())
appRouterGroup.AuthRouterGroup.PUT("/inbox/:id/read", h.InboxHandler.MarkInboxAsRead())
appRouterGroup.AuthRouterGroup.DELETE("/inbox/:id", h.InboxHandler.DeleteInbox())
appRouterGroup.AuthRouterGroup.DELETE("/inbox", h.InboxHandler.ClearInbox())
}
Other source-confirmed unguarded privileged surfaces include:
/api/panel/comments*/api/addConnect/api/delConnect/:id/api/migration/*/api/backup/export
Service-layer authorization often checks only admin role. For example, internal/service/inbox/inbox.go:
func (inboxService *InboxService) ensureAdmin(ctx context.Context) error {
userid := viewer.MustFromContext(ctx).UserID()
user, err := inboxService.commonService.CommonGetUserByUserId(ctx, userid)
if err != nil {
return err
}
if !user.IsAdmin {
return errors.New(commonModel.NO_PERMISSION_DENIED)
}
return nil
}
The backup export path is a stronger variant because it discards token metadata before authorization. internal/handler/backup/backup.go reparses a query token and rebuilds a bare viewer from only the user ID:
func (backupHandler *BackupHandler) ExportBackup() gin.HandlerFunc {
return res.Execute(func(ctx *gin.Context) res.Response {
token := ctx.Query("token")
claims, err := jwtUtil.ParseToken(token)
if err != nil { ... }
reqCtx := viewer.WithContext(context.Background(), viewer.NewUserViewer(claims.Userid))
if err := backupHandler.backupService.ExportBackup(ctx, reqCtx); err != nil { ... }
return res.Response{Msg: commonModel.EXPORT_BACKUP_SUCCESS}
})
}
This drops token type, scopes, audience, and token ID before the backup service runs.
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
curl -sS -X POST "http://127.0.0.1:6277/api/init/owner" \
-H 'Content-Type: application/json' \
-d…
- Record
GHSA-4h9q-p5j4-xvvh- CVSS 3.1
- 7.6 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L - Weakness
- CWE-285
- Updated
- 2026-11-02
OSVGO-2026-5123 No score
Ech0: Scoped admin access tokens can bypass least-privilege controls on privileged endpoints, including backup export in github.com/lin-snow/ech0
Ech0: Scoped admin access tokens can bypass least-privilege controls on privileged endpoints, including backup export in github.com/lin-snow/ech0.
NOTE: The source advisory for this report contains additional versions that could not be automatically mapped to standard Go module versions.
(If this is causing false-positive reports from vulnerability scanners, please suggest an edit to the report.)
The additional affected modules and versions are: github.com/lin-snow/ech0 before v4.3.5.
- Record
GO-2026-5123- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
github.com/lin-snow/ech0Go |
before 4.3.5 | 4.3.5 |
github.com/lin-snow/ech0Go |
All versions | None known |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-79667 is a high vulnerability (CVSS 7.2) in Lin-snow Ech0, published April 10, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.32%, the 25th percentile. Fixed in github.com/lin-snow/ech0 4.3.5.
References
github.com/lin-snow/Ech0/security/advisories/GHSA-4h9q-p5j4-xvvh
vulncheck.com/advisories/ech0-before-authentication-bypass-via-scope-enforcement
github.com/lin-snow/Ech0/releases/tag/v4.3.5
github.com/advisories/GHSA-4h9q-p5j4-xvvh
nvd.nist.gov/vuln/detail/CVE-2026-79667
github.com/advisories/GHSA-vgpj-v99m-7h5j
github.com/CVEProject/cvelistV5/tree/main/cves/2026/79xxx/CVE-2026-79667.json
github.com/lin-snow/Ech0
Left out here: the rest of 2 source descriptions. The JSON record has them.