Harden server-side input validation and auth defaults (#18018)
## Summary - **File storage (LocalDriver):** Add realpath resolution and symlink rejection to `writeFile`, `downloadFile`, and `downloadFolder` — brings them in line with the existing `readFile` protections. Includes unit tests. - **JWT:** Pin signing/verification to HS256 explicitly. - **Auth:** Revoke active refresh tokens when a user changes their password. - **Logic functions:** Validate `handlerName` as a safe JS identifier at both DTO and runtime level, preventing injection into the generated runner script. - **User entity:** Remove `passwordHash` from the GraphQL schema (`@Field` decorator removed, column stays). - **Query params:** Use `crypto.randomBytes` instead of `Math.random` for SQL parameter name generation. - **Exception filter:** Mirror the request `Origin` header instead of sending `Access-Control-Allow-Origin: *`. ## Test plan - [x] `local.driver.spec.ts` — writeFile rejects symlinks, downloadFile rejects paths outside storage - [ ] Verify JWT auth flow still works (login, token refresh) - [ ] Verify password change invalidates existing sessions - [ ] Verify logic function creation with valid/invalid handler names - [ ] Verify file upload/download in dev environment Made with [Cursor](https://cursor.com) --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
This commit is contained in:
@@ -11,7 +11,7 @@ import { PasswordUpdateNotifyEmail } from 'twenty-emails';
|
||||
import { PermissionFlagType } from 'twenty-shared/constants';
|
||||
import { AppPath } from 'twenty-shared/types';
|
||||
import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils';
|
||||
import { Repository } from 'typeorm';
|
||||
import { IsNull, Repository } from 'typeorm';
|
||||
|
||||
import { NodeEnvironment } from 'src/engine/core-modules/twenty-config/interfaces/node-environment.interface';
|
||||
|
||||
@@ -618,6 +618,18 @@ export class AuthService {
|
||||
passwordHash: newPasswordHash,
|
||||
});
|
||||
|
||||
// Invalidate all existing refresh tokens for this user across all workspaces
|
||||
await this.appTokenRepository.update(
|
||||
{
|
||||
userId,
|
||||
type: AppTokenType.RefreshToken,
|
||||
revokedAt: IsNull(),
|
||||
},
|
||||
{
|
||||
revokedAt: new Date(),
|
||||
},
|
||||
);
|
||||
|
||||
const emailTemplate = PasswordUpdateNotifyEmail({
|
||||
userName: `${user.firstName} ${user.lastName}`,
|
||||
email: user.email,
|
||||
|
||||
Reference in New Issue
Block a user