Uses Public Default Authentication Secrets
Self Checks
- I have read the Contributing Guide.
- I have searched for existing issues search for existing issues, including closed ones.
- I can provide the report in English if needed to help more contributors participate in the discussion.
- Please do not modify this template :) and fill in all the required fields.
Aitoearn version
Commit d3aa8bea5b146a8675607cf0144d891aad3e9683 and earlier versions
Please select your platform
Mac
Steps to reproduce
AiToEarn Uses Public Default Authentication Secrets
Package
AiToEarn
Affected versions
Commit d3aa8bea5b146a8675607cf0144d891aad3e9683 and earlier versions
containing the affected code.
Patched versions
Unknown.
Description
Summary
AiToEarn contains public default values for authentication secrets. The
Electron server uses a static fallback for AUTH_SECRET to sign and verify
JWTs. The JWT payload contains isManager, and ManagerGuard grants manager
access when this claim is true.
The backend configuration also contains a static internalToken. The shared
authentication guard accepts this value directly as a Bearer token without
JWT verification or user lookup. Internal controllers protected by
@Internal() therefore rely on this publicly known value as their only
authentication factor.
Details
| Component | File | Issue |
|---|---|---|
| Electron server | project/aitoearn-electron/server/src/auth/auth.module.ts |
Static fallback for AUTH_SECRET |
| Electron server | project/aitoearn-electron/server/src/auth/manager.guard.ts |
Trusts isManager after JWT verification |
| Backend services | project/aitoearn-backend/apps/aitoearn-server/config/config.yaml |
Static auth.secret and auth.internalToken defaults |
| Shared backend auth | project/aitoearn-backend/libs/aitoearn-auth/src/aitoearn-auth.guard.ts |
Accepts internalToken directly |
Vulnerable Code
project/aitoearn-electron/server/src/auth/auth.module.ts:
JwtModule.register({
global: true,
secret: process.env.AUTH_SECRET || "<public static default redacted>",
signOptions: { expiresIn: '30d' },
})The application places the manager flag inside the JWT:
const payload: TokenInfo = {
phone: tokenInfo.phone,
id: tokenInfo.id,
name: tokenInfo.name,
isManager: tokenInfo.isManager,
};
return this.jwtService.sign(payload);ManagerGuard then accepts the authorization decision from the token:
const payload = await this.jwtService.verifyAsync(token, {
secret: process.env.AUTH_SECRET,
});
if (!payload.isManager) {
throw new UnauthorizedException();
}The backend configuration also publishes static authentication values:
auth:
secret: <public static default redacted>
internalToken: <public static default redacted>The shared guard accepts the internal token without establishing a user:
if (token === this.options.internalToken) {
return true;
}PoC
Run only against a local test deployment.
JWT manager authorization
- Leave
AUTH_SECRETunset in the Electron server. - Create a JWT with the public fallback key and a payload containing
isManager: true. - Send the token as
Authorization: Bearer <token>to a route protected by@Manager(), such as the manager creation route. - Repeat the test with a unique random
AUTH_SECRET.
Example token-generation pseudocode:
const token = jwt.sign(
{ id: '<test-id>', isManager: true },
'<public static default redacted>',
{ expiresIn: '30d' },
);Expected secure result: the forged token is rejected. The affected result is
that the request passes ManagerGuard and reaches the manager-only handler.
Internal bearer token
- Start the backend with the checked-in
internalTokenvalue unchanged. - Send that value as a Bearer token to an endpoint protected by
@Internal(). - For example, test the AI draft-generation internal endpoints using a body that satisfies the endpoint DTO.
- Repeat with a newly generated internal token.
Expected secure result: an external request without an explicitly authorized service credential is rejected. The affected result is that the static token passes the guard without JWT verification, API-key resolution, or user lookup.
Attack Scenario
- An attacker reads the public repository and obtains the default values.
- The deployment does not override the corresponding environment/configuration values.
- The attacker signs a JWT with
isManager: true, or sends the defaultinternalTokenas a Bearer token. - The server accepts the token as an authenticated manager or internal caller.
Impact
The Electron JWT fallback may allow unauthorized access to manager-only
handlers, including manager administration operations. The backend
internalToken may allow unauthorized access to internal service endpoints,
including operations that accept a caller-supplied userId.
The backend auth.secret path additionally uses the token id to resolve an
open user record. Its exact impact should be verified against the deployed
token-issuing path, but the checked-in value is not suitable as a production
JWT secret.
Recommended Fix
- Remove all static authentication fallbacks from source-controlled configuration.
- Fail closed when
AUTH_SECRET,auth.secret, orinternalTokenis absent or unchanged from a development value. - Generate instance-specific cryptographically random secrets during secure deployment and store them outside the repository.
- Replace the exposed values and invalidate tokens issued with them.
- Do not use a bearer string as an implicit internal identity; authenticate service callers with scoped, rotatable credentials and enforce service-side authorization.
- Add regression tests proving that default or missing secrets cannot start a production deployment and that forged manager/internal requests are rejected.
References
- JWT fallback in the Electron server
- JWT manager authorization
- JWT payload construction
- Manager-only handlers
- Backend authentication defaults
- Direct internal-token acceptance
- Internal AI endpoints
✔️ Expected Behavior
...
❌ Actual Behavior
...
Source: yikart/AiToEarn