diff --git a/Controller/Controller.php b/Controller/Controller.php index 86a17989..9c4a5641 100644 --- a/Controller/Controller.php +++ b/Controller/Controller.php @@ -9,6 +9,8 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Config\ConfigCache; use Symfony\Component\Config\Resource\FileResource; +use Symfony\Component\Filesystem\Exception\IOException; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @author William DURAND @@ -143,7 +145,11 @@ public function getTranslationsAction(Request $request, $domain, $_format) 'include_config' => true, )); - $cache->write($content, $resources); + try { + $cache->write($content, $resources); + } catch (IOException $e) { + throw new NotFoundHttpException(); + } } $response = new Response( diff --git a/Tests/Controller/ControllerTest.php b/Tests/Controller/ControllerTest.php index 08aeb21b..1f8b5469 100644 --- a/Tests/Controller/ControllerTest.php +++ b/Tests/Controller/ControllerTest.php @@ -171,4 +171,30 @@ public function testGetTranslationsWithNumericKeys() JSON , $response->getContent()); } + + public function testGetTranslationsWithPathTraversalAttack() + { + $client = static::createClient(); + + // 1. `evil.js` is not accessible + $crawler = $client->request('GET', '/translations?locales=randomstring/../../evil'); + $response = $client->getResponse(); + + $this->assertEquals(404, $response->getStatusCode()); + + // 2. let's create a random directory with a randome js file + $crawler = $client->request('GET', '/translations?locales=randomstring/something'); + $response = $client->getResponse(); + + $this->assertFileExists(sprintf('%s/%s/messages.randomstring/something.js', + $client->getKernel()->getCacheDir(), + 'bazinga-js-translation' + )); + + // 3. path traversal attack + $crawler = $client->request('GET', '/translations?locales=randomstring/../../evil'); + $response = $client->getResponse(); + + $this->assertEquals(200, $response->getStatusCode()); + } }