Files
twenty/packages/twenty-front/src/modules/settings/components/SettingsProtectedRouteWrapper.tsx
T
Félix Malfait cebcf4f1f5 Prevent csv export injections (#14347)
**Small Security Issue:** CSV exports were vulnerable to formula
injection attacks when users entered values starting with =, +, -, or @.
(only happens if a logged-in user injects corrupted data)

Solution:
- Added ZWJ (Zero-Width Joiner) protection that prefixes dangerous
values with invisible Unicode character
- This is the best way to preserve original data while preventing Excel
from executing formulas
- Added import cleanup to restore original values when re-importing
 
Changes:
- New sanitizeValueForCSVExport() function for security
- Updated all CSV export paths to use both security + formatting
functions
- Added comprehensive tests covering attack vectors and international
characters
- Also added cursor rules for better code consistency

---------

Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
2025-09-08 17:57:46 +02:00

43 lines
1.5 KiB
TypeScript

import { useIsLogged } from '@/auth/hooks/useIsLogged';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { SettingsPath } from '@/types/SettingsPath';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { type ReactNode } from 'react';
import { Navigate, Outlet } from 'react-router-dom';
import {
type FeatureFlagKey,
type PermissionFlagType,
} from '~/generated/graphql';
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
type SettingsProtectedRouteWrapperProps = {
children?: ReactNode;
settingsPermission?: PermissionFlagType;
requiredFeatureFlag?: FeatureFlagKey;
};
export const SettingsProtectedRouteWrapper = ({
children,
settingsPermission,
requiredFeatureFlag,
}: SettingsProtectedRouteWrapperProps) => {
const isLoggedIn = useIsLogged();
const hasPermission = useHasPermissionFlag(settingsPermission);
const requiredFeatureFlagEnabled = useIsFeatureEnabled(
requiredFeatureFlag || null,
);
if (!isLoggedIn) {
return null;
}
// TODO: this should be part of PageChangeEffect as otherwise we will have multiple sources of redirection that can:
// - conflict (race conditions)
// - degrade performance as we will redirect multiple times
if ((requiredFeatureFlag && !requiredFeatureFlagEnabled) || !hasPermission) {
return <Navigate to={getSettingsPath(SettingsPath.ProfilePage)} replace />;
}
return children ?? <Outlet />;
};