Skip to content

[Security] Hardcoded JWT fallback secret enables token forgery #97

Description

@28Hus

[Security] Hardcoded JWT fallback secret enables token forgery

Summary

The JWT utility uses the predictable default secret secret when JWT_SECRET is empty. An attacker who knows this value can generate valid HS256 signatures for tokens processed by affected authentication paths, subject to any additional authorization and database checks.

Affected Version

Affected version: commit c3413ac19b755107b2b962e5459aa77ce5ebd4b2 on branch main.

Technical Details and Root Cause

At api/common/utils/jwt/jwt.go:12, the signing key is configured as []byte(env.String("JWT_SECRET", "secret")) (source). The environment helper uses the configured default when the environment value is empty (env.go:44, env.go:49).

The key is used in the JWT signing and verification chain (jwt.go:21, jwt.go:31, jwt.go:36:

   17: 		"eid":     eid,
   18: 		"exp":     time.Now().Add(168 * time.Hour).Unix(),
   19: 	}
   20: 
   21: 	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
   22: 	return token.SignedString(secretKey)
   23: }

Exact source

The same key is also referenced by delegated upload JWT handling and batch-upload authentication paths (upload_delegate.go:45, upload_delegate.go:61, batch_upload_auth.go:65, batch_upload_auth.go:99).

Impact

An attacker needs access to a deployment where JWT_SECRET is empty and knowledge of the default value secret; no credential is needed to calculate a valid signature. Forged tokens may be accepted by JWT-based authentication consumers, potentially enabling impersonation or unauthorized access to data available through those consumers.

The primary authentication path additionally checks users.access_token, user identity, account status, and database role (user.go:131, user.go:136, auth.go:149, auth.go:162); whether the default alone enables unauthorized access therefore depends on deployment configuration and the specific consuming path.

Reproduction Conditions

Configure a deployment with JWT_SECRET empty, confirm that the JWT key resolves to the default secret, and trace an existing JWT authentication or batch-upload path. Validate whether an HS256 token signed with secret passes that path’s signature and subsequent identity, status, role, or database-token checks.

Recommended Fix

  • Remove the committed "secret" fallback and fail closed when JWT_SECRET is missing or empty.
  • Require a unique, high-entropy secret for every deployment and rotate the exposed value.
  • Store signing keys in a server-side secret or key manager, not in source-controlled configuration.
  • Use separate, scoped keys where delegated upload authentication has different trust requirements.
  • Keep credential claims minimal and never derive signing keys from passwords or password hashes.

This observation was identified during our ongoing research on authentication token security. We would be happy to provide additional technical details or assistance with preparing a patch. Please feel free to contact us if any clarification is needed.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions