Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Hunting Vulnerabilities in Symfony with LLMs

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

Hunting Vulnerabilities in Symfony with LLMs

Talk given at the
SymfonyOnline June 2026 - Online

Hackers are already using Large Language Models to map your attack surface, it’s time you used them to defend it.

While we’ve spent years trying to write the perfect regex or rule-set to catch bugs, LLMs have unlocked a terrifyingly effective ability to understand the intent and context of our Symfony and PHP code.

This session dives into the practical reality of using AI as an autonomous security researcher to uncover deep-seated vulnerabilities in Symfony applications that traditional tools simply cannot see.

We will explore how to architect a high-speed security pipeline that feeds your codebase to an LLM to detect broken access control, complex injection paths, and logic flaws in real-time.

You’ll walk away with a battle-tested strategy to weaponize AI against your own technical debt, turning the most unpredictable technology of our time into your most meticulous security auditor.

Avatar for Vincent Amstoutz

Vincent Amstoutz

June 15, 2026

More Decks by Vincent Amstoutz

Other Decks in Programming

Transcript

  1. ENGINEERING PHP, JS, Go, Rust, C DevOps & SRE PRODUCT

    Agile Management UX / UI Design SUPPORT Consultancy, Training & Application Maintenance API, Web, Cloud & AI experts @vinceAmstoutz
  2. @vinceAmstoutz Why Traditional Tools Fail? Syntax vs. Intent Legacy SAST

    tools rely on "Regex patterns". Context is King LLMs understand the deep relationship between a Controller, a Voter, and the Database.
  3. 1 Fast zero-day discovery. Hyper-Accelerated Discovery Instant Weaponization Fast zero-day

    implementation. 2 3 Democratization of Elite Hacking It levels up low-skilled attackers. Problems caused @vinceAmstoutz
  4. @vinceAmstoutz Beyond Simple Bugs $sortBy = $request->query->get('sort_by', 'name'); $direction =

    $request->query->get('direction', 'ASC'); // src/Controller/ProductController.php 1 2 // ... 3 4 class ProductController extends AbstractController 5 { 6 #[Route('/products', name: 'app_products', methods: ['GET'])] 7 public function list(Request $request, ProductRepository $repository): Response 8 { 9 10 11 12 $products = $repository->findSortedProducts($sortBy, $direction); 13 14 return $this->render('product/list.html.twig', ['products' => $products]); 15 } 16 } 17 $products = $repository->findSortedProducts($sortBy, $direction); // src/Controller/ProductController.php 1 2 // ... 3 4 class ProductController extends AbstractController 5 { 6 #[Route('/products', name: 'app_products', methods: ['GET'])] 7 public function list(Request $request, ProductRepository $repository): Response 8 { 9 $sortBy = $request->query->get('sort_by', 'name'); 10 $direction = $request->query->get('direction', 'ASC'); 11 12 13 14 return $this->render('product/list.html.twig', ['products' => $products]); 15 } 16 } 17 return $this->render('product/list.html.twig', ['products' => $products]); // src/Controller/ProductController.php 1 2 // ... 3 4 class ProductController extends AbstractController 5 { 6 #[Route('/products', name: 'app_products', methods: ['GET'])] 7 public function list(Request $request, ProductRepository $repository): Response 8 { 9 $sortBy = $request->query->get('sort_by', 'name'); 10 $direction = $request->query->get('direction', 'ASC'); 11 12 $products = $repository->findSortedProducts($sortBy, $direction); 13 14 15 } 16 } 17 Complex Injection Paths
  5. @vinceAmstoutz Beyond Simple Bugs // src/Repository/ProductRepository.php // ... class ProductRepository

    extends ServiceEntityRepository { // ... public function findSortedProducts(string $sortBy, string $direction): array { return $this->createQueryBuilder('p') ->orderBy('p.' . $sortBy, $direction) ->getQuery() ->getResult(); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ->orderBy('p.' . $sortBy, $direction) // src/Repository/ProductRepository.php 1 2 // ... 3 4 class ProductRepository extends ServiceEntityRepository { 5 6 // ... 7 8 public function findSortedProducts(string $sortBy, string $direction): array 9 { 10 return $this->createQueryBuilder('p') 11 12 ->getQuery() 13 ->getResult(); 14 } 15 } 16 Complex Injection Paths
  6. @vinceAmstoutz Beyond Simple Bugs // src/Controller/InvoiceController.php // ... #[Route('/api')] #[IsGranted('ROLE_USER')]

    class InvoiceController extends AbstractController { #[Route('/invoice/{id}', methods: ['GET'])] public function show(Invoice $invoice): JsonResponse { return $this->json($invoice); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Broken Access Control
  7. @vinceAmstoutz Beyond Simple Bugs // src/Controller/ProfileController.php // ... class ProfileController

    extends AbstractController { #[Route('/profile/update-password', methods: ['POST'])] public function updatePassword(...): Response { $targetUserId = $request->request->get('user_id'); $userToUpdate = $userRepository->find($targetUserId); // Update password etc return $this->redirectToRoute('app_profile_success'); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Logic Flaws
  8. PoC Auto-generating exploit code to verify 4. Audit Multi-agent analysis:

    Attacker vs. Reviewer loop 3. Mapping Retrieves related Services, Voters, Entities, etc 2. Ingestion Feeds project files 1. The Autonomous Researcher Pipeline @vinceAmstoutz
  9. @vinceAmstoutz Configuration composer require symfony/ai-anthropic-platform # config/packages/ai.yaml ai: platform: anthropic:

    api_key: '%env(ANTHROPIC_API_KEY)%' # config/packages/symfony_security_auditor.yaml symfony_security_auditor: model: 'claude-sonnet-4-6'
  10. @vinceAmstoutz Configuration Symfony\AI\AiBundle\AiBundle::class => ['all' => true], # config/bundles.php 1

    2 return [ 3 // ... 4 5 VinceAmstoutz\SymfonySecurityAuditor\SymfonySecurityAuditorBundle::class => [ 6 'dev' => true, 7 'test' => true 8 ], 9 ]; 10 VinceAmstoutz\SymfonySecurityAuditor\SymfonySecurityAuditorBundle::class => [ 'dev' => true, 'test' => true ], # config/bundles.php 1 2 return [ 3 // ... 4 Symfony\AI\AiBundle\AiBundle::class => ['all' => true], 5 6 7 8 9 ]; 10
  11. @vinceAmstoutz Demo: CI job on: schedule: - cron: '0 2

    * * 1' # weekly on Monday at 02:00 UTC # .github/workflows/security-audit.yaml 1 name: Security Audit 2 3 4 5 6 7 jobs: 8 audit: 9 name: Symfony Security Audit 10 runs-on: ubuntu-latest 11 steps: 12 - uses: actions/checkout@v6 13 14 - uses: shivammathur/setup-php@v2 15 with: 16 php-version: '8.3' # Or 8.4 or 8.5 17 18 - name: Install dependencies 19 run: composer install --no-interaction --prefer-dist --no-progress 20 21 - name: Run security audit 22 env: 23 ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} 24 run: | 25 php bin/console audit:run 26 jobs: audit: name: Symfony Security Audit runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: shivammathur/setup-php@v2 with: php-version: '8.3' # Or 8.4 or 8.5 - name: Install dependencies run: composer install --no-interaction --prefer-dist --no-progress # .github/workflows/security-audit.yaml 1 name: Security Audit 2 3 on: 4 schedule: 5 - cron: '0 2 * * 1' # weekly on Monday at 02:00 UTC 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 - name: Run security audit 22 env: 23 ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} 24 run: | 25 php bin/console audit:run 26 - name: Run security audit env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} run: | php bin/console audit:run # .github/workflows/security-audit.yaml 1 name: Security Audit 2 3 on: 4 schedule: 5 - cron: '0 2 * * 1' # weekly on Monday at 02:00 UTC 6 7 jobs: 8 audit: 9 name: Symfony Security Audit 10 runs-on: ubuntu-latest 11 steps: 12 - uses: actions/checkout@v6 13 14 - uses: shivammathur/setup-php@v2 15 with: 16 php-version: '8.3' # Or 8.4 or 8.5 17 18 - name: Install dependencies 19 run: composer install --no-interaction --prefer-dist --no-progress 20 21 22 23 24 25 26
  12. Can't verify exploitability Code sent to provider unless local models

    such as Ollama Cost on large codebases Cons Finds logic-level flaws SAST tools structurally can't Dual-agent loop cuts false positives Provider-agnostic Low cost VS a manual pentest or commercial DAST tool Pros @vinceAmstoutz