Skip to content

Fix hardcoded JWT secrets in .env.example and config/jwt.php (CWE-798) - #91

Open
saaa99999999 wants to merge 1 commit into
francescomalatesta:masterfrom
saaa99999999:fix/hardcoded-jwt-secret
Open

Fix hardcoded JWT secrets in .env.example and config/jwt.php (CWE-798)#91
saaa99999999 wants to merge 1 commit into
francescomalatesta:masterfrom
saaa99999999:fix/hardcoded-jwt-secret

Conversation

@saaa99999999

Copy link
Copy Markdown

Summary

Removed hardcoded JWT signing secret defaults from .env.example and config/jwt.php. Added startup validation in AppServiceProvider that rejects empty, known-default, and short JWT secrets.

Details

  • .env.example:48: JWT_SECRET=my-dummy-token ??empty with php artisan jwt:secret generation instructions.
  • config/jwt.php:28: env('JWT_SECRET', 'my-dummy-jwt-token') ??env('JWT_SECRET') (no hardcoded code-level fallback).
  • app/Providers/AppServiceProvider.php: Added boot() validation that rejects:
    • Empty/null JWT_SECRET
    • Known weak values (my-dummy-token, my-dummy-jwt-token, secret, changeme, jwt_secret, your-secret-key)
    • Keys shorter than 32 characters

Security Impact

This project uses tymon/jwt-auth with symmetric HMAC signing. The hardcoded secret my-dummy-jwt-token was present in two places:

  1. As the default value in .env.example (template developers copy)
  2. As the second argument to env() in config/jwt.php (code-level fallback if the env var is missing)

The code-level fallback is especially dangerous: even if no .env file exists, the application would silently start and use my-dummy-jwt-token to sign and verify all JWT tokens. Anyone who knows this key ??which is visible in the public GitHub repository ??can forge valid authentication tokens for any user.

Before/After

config/jwt.php

- 'secret' => env('JWT_SECRET', 'my-dummy-jwt-token'),
+ 'secret' => env('JWT_SECRET'),

.env.example

- JWT_SECRET=my-dummy-token
+ # Generate: php artisan jwt:secret
+ # Or: php -r "echo base64_encode(random_bytes(64));"
+ JWT_SECRET=

app/Providers/AppServiceProvider.php

public function boot()
{
    $jwtSecret = Config::get('jwt.secret');
    $knownWeak = [
        '', 'my-dummy-token', 'my-dummy-jwt-token',
        'secret', 'changeme', 'jwt_secret', 'your-secret-key',
    ];
    if (empty($jwtSecret) || in_array($jwtSecret, $knownWeak, true)) {
        throw new \RuntimeException(
            'JWT_SECRET is not set or uses a known default value. ' .
            'Set JWT_SECRET in your .env file. ' .
            'Generate a secure key: php artisan jwt:secret'
        );
    }
    if (strlen($jwtSecret) < 32) {
        throw new \RuntimeException(
            'JWT_SECRET must be at least 32 characters. ' .
            'Current length: ' . strlen($jwtSecret) . '.'
        );
    }
}

Removed the default hardcoded JWT secret fallbacks from .env.example
and config/jwt.php. Added startup validation in AppServiceProvider
that rejects empty, known-default, and short JWT secrets.
@saaa99999999

Copy link
Copy Markdown
Author

CVE Request — Action Needed from Maintainer

This PR fixes security vulnerabilities. To assign a CVE number:

GitHub only issues CVEs from the official upstream repository, not from forks.

Please:

  1. Go to this repo → SecurityAdvisoriesNew draft security advisory
  2. Add @saaa99999999 as a collaborator
  3. I will populate the full vulnerability details (CVSS, CWE, data flow, PoC) and submit the CVE request

If you prefer, I can submit the CVE via MITRE (cveform.mitre.org) instead — just let me know.

Thank you for reviewing this PR!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant