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>
This commit is contained in:
@@ -8,12 +8,12 @@ import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState
|
||||
import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { SettingsPath } from '@/types/SettingsPath';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { motion } from 'framer-motion';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { SettingsPath } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
const StyledCommandMenuContent = styled.div`
|
||||
|
||||
@@ -20,7 +20,6 @@ import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { useRef } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { AppBasePath } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { IconChevronLeft, IconX } from 'twenty-ui/display';
|
||||
import { Button } from 'twenty-ui/input';
|
||||
@@ -106,8 +105,8 @@ export const CommandMenuTopBar = () => {
|
||||
|
||||
const location = useLocation();
|
||||
const isButtonVisible =
|
||||
!location.pathname.startsWith(`${AppBasePath.Root}objects/`) &&
|
||||
!location.pathname.startsWith(`${AppBasePath.Root}object/`);
|
||||
!location.pathname.startsWith('/objects/') &&
|
||||
!location.pathname.startsWith('/object/');
|
||||
|
||||
const backButtonAnimationDuration =
|
||||
contextChips.length > 0 ? theme.animation.duration.instant : 0;
|
||||
|
||||
Reference in New Issue
Block a user