Skip to content

Commit baf31e5

Browse files
committed
Fix security issue on CsvEncoder
1 parent 592c8fe commit baf31e5

File tree

3 files changed

+75
-2
lines changed

3 files changed

+75
-2
lines changed

src/Symfony/Component/Serializer/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ CHANGELOG
1111
* added an optional `string $format = null` argument to `AbstractNormalizer::instantiateObject`
1212
* added an optional `array $context = array()` to `Serializer::supportsNormalization`, `Serializer::supportsDenormalization`,
1313
`Serializer::supportsEncoding` and `Serializer::supportsDecoding`
14+
* added optional `bool $escapeFormulaValues = true` argument to `CsvEncoder::__construct`
1415

1516
3.4.0
1617
-----

src/Symfony/Component/Serializer/Encoder/CsvEncoder.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,28 @@ class CsvEncoder implements EncoderInterface, DecoderInterface
2727
const ESCAPE_CHAR_KEY = 'csv_escape_char';
2828
const KEY_SEPARATOR_KEY = 'csv_key_separator';
2929
const HEADERS_KEY = 'csv_headers';
30+
const FORMULAS_START_CHARACTERS = array('=', '-', '+', '@');
3031

3132
private $delimiter;
3233
private $enclosure;
3334
private $escapeChar;
3435
private $keySeparator;
36+
private $escapeFormulaValues;
3537

3638
/**
3739
* @param string $delimiter
3840
* @param string $enclosure
3941
* @param string $escapeChar
4042
* @param string $keySeparator
43+
* @param bool $escapeFormulaValues
4144
*/
42-
public function __construct($delimiter = ',', $enclosure = '"', $escapeChar = '\\', $keySeparator = '.')
45+
public function __construct($delimiter = ',', $enclosure = '"', $escapeChar = '\\', $keySeparator = '.', $escapeFormulaValues = true)
4346
{
4447
$this->delimiter = $delimiter;
4548
$this->enclosure = $enclosure;
4649
$this->escapeChar = $escapeChar;
4750
$this->keySeparator = $keySeparator;
51+
$this->escapeFormulaValues = $escapeFormulaValues;
4852
}
4953

5054
/**
@@ -186,7 +190,11 @@ private function flatten(array $array, array &$result, $keySeparator, $parentKey
186190
if (is_array($value)) {
187191
$this->flatten($value, $result, $keySeparator, $parentKey.$key.$keySeparator);
188192
} else {
189-
$result[$parentKey.$key] = $value;
193+
if ($this->escapeFormulaValues && \in_array(mb_substr($value, 0, 1), self::FORMULAS_START_CHARACTERS, true)) {
194+
$result[$parentKey.$key] = "\t".$value;
195+
} else {
196+
$result[$parentKey.$key] = $value;
197+
}
190198
}
191199
}
192200
}

src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,70 @@ public function testEncodeCustomHeaders()
173173
$this->assertEquals($csv, $this->encoder->encode($value, 'csv', $context));
174174
}
175175

176+
public function testEncodeFormulaValues()
177+
{
178+
$this->assertEquals(<<<'CSV'
179+
0
180+
" =2+3"
181+
182+
CSV
183+
, $this->encoder->encode(array('=2+3'), 'csv'));
184+
185+
$this->assertEquals(<<<'CSV'
186+
0
187+
" -2+3"
188+
189+
CSV
190+
, $this->encoder->encode(array('-2+3'), 'csv'));
191+
192+
$this->assertEquals(<<<'CSV'
193+
0
194+
" +2+3"
195+
196+
CSV
197+
, $this->encoder->encode(array('+2+3'), 'csv'));
198+
199+
$this->assertEquals(<<<'CSV'
200+
0
201+
" @MyDataColumn"
202+
203+
CSV
204+
, $this->encoder->encode(array('@MyDataColumn'), 'csv'));
205+
}
206+
207+
public function testDoNotEncodeFormulaValues()
208+
{
209+
$this->encoder = new CsvEncoder(',', '"', '\\', '.', false);
210+
211+
$this->assertEquals(<<<'CSV'
212+
0
213+
=2+3
214+
215+
CSV
216+
, $this->encoder->encode(array('=2+3'), 'csv'));
217+
218+
$this->assertEquals(<<<'CSV'
219+
0
220+
-2+3
221+
222+
CSV
223+
, $this->encoder->encode(array('-2+3'), 'csv'));
224+
225+
$this->assertEquals(<<<'CSV'
226+
0
227+
+2+3
228+
229+
CSV
230+
, $this->encoder->encode(array('+2+3'), 'csv'));
231+
232+
$this->assertEquals(<<<'CSV'
233+
0
234+
@MyDataColumn
235+
236+
CSV
237+
, $this->encoder->encode(array('@MyDataColumn'), 'csv'));
238+
}
239+
176240
public function testSupportsDecoding()
177241
{
178242
$this->assertTrue($this->encoder->supportsDecoding('csv'));

0 commit comments

Comments
 (0)