In this article
Créer un résumé des actualités de sécurité avec un agent IA CrewAI
Parcourir de nombreuses sources d’actualités sur la sécurité et bases de données de vulnérabilités est un travail fastidieux. Mais avec l’essor des workflows d’IA agentique, nous pouvons confier cette tâche à un LLM. Cet article montre comment utiliser le framework open source CrewAI pour créer un agent IA qui sélectionne les actualités de sécurité.
Des agents IA pour sélectionner les actualités de sécurité
Pour l’application que nous allons créer, nous allons nous concentrer sur la sélection de nouvelles vulnérabilités de sécurité dans la Snyk Vulnerability Database, afin de créer un fil d’actualités sur la sécurité.
Notre agent IA sera un outil en ligne de commande qui ouvre la page Web de la Snyk Vulnerability Database pour un écosystème donné (nous utiliserons l’écosystème JavaScript npm) et sélectionne les trois rapports CVE les plus pertinents et, selon lui, les plus importants.
Bien démarrer avec CrewAI
Pour commencer, nous allons créer un répertoire de projet à l’emplacement de votre choix dans votre environnement de développement local, puis y initialiser le framework CrewAI.
Voici les prérequis :
Le gestionnaire de packages uv est installé et disponible localement
Un environnement d’exécution Python >= 3.x (peut être installé avec
uv)
Dans le répertoire de votre choix, commençons par installer la bibliothèque et les outils crewai :
uv tool install crewaiAjoutez-la ensuite à l’environnement de votre shell pour pouvoir exécuter la commande crewai comme un exécutable global :
uv tool update-shellNous pouvons maintenant créer la structure d’un nouveau projet crewai :
crewai create crew <your_project_name>Installez ensuite les dépendances du projet en exécutant cette commande :
crewai installLe répertoire du projet créé devrait maintenant ressembler à ceci :

Dans les grandes lignes, CrewAI utilise un fichier crew.py qui définit les agents et les tâches :
@agent
def researcher(self) -> Agent:
return Agent(
config=self.agents_config['researcher'], # type: ignore[index]
verbose=True
)
@agent
def reporting_analyst(self) -> Agent:
return Agent(
config=self.agents_config['reporting_analyst'], # type: ignore[index]
verbose=True
)
Le même fichier contient également les tâches que nous voulons confier à ces agents :
@task
def research_task(self) -> Task:
return Task(
config=self.tasks_config['research_task'], # type: ignore[index]
)
@task
def reporting_task(self) -> Task:
return Task(
config=self.tasks_config['reporting_task'], # type: ignore[index]
output_file='report.md'
)Le fichier main.py exporte plusieurs fonctions, comme run(), train() et d’autres, qui invoquent les agents et leur fournissent les données nécessaires à leur travail.
Voici le déroulement du lancement des agents dans le fichier Python principal :
def run():
"""
Run the crew.
"""
inputs = {
'topic': 'AI LLMs',
'current_year': str(datetime.now().year)
}
try:
SecurityNewsSummary().crew().kickoff(inputs=inputs)
except Exception as e:
raise Exception(f"An error occurred while running the crew: {e}")Tout ce qui précède décrit la structure de projet par défaut créée par CrewAI. Nous allons toutefois la modifier pour définir nos propres agents et tâches, et créer un outil personnalisé que les agents pourront appeler.
Créer des workflows agentiques personnalisés avec CrewAI
Nous allons modifier trois éléments principaux du répertoire de projet CrewAI :
Modifications des agents dans
config/agents.yamlModifications des tâches dans
config/tasks.yamlModifications du programme Python CrewAI principal crew.py
Nous allons également créer un outil personnalisé dans le répertoire tools/ pour analyser le code HTML d’une page Web à l’aide de BeautifulSoup, une bibliothèque Python populaire.
Agents IA
En règle générale, il est préférable de décomposer les tâches confiées aux agents IA en éléments aussi petits que possible. Comme en génie logiciel et en conception, diviser les problèmes complexes en problèmes plus simples est une approche efficace.
Pour mettre ce conseil en pratique, nous allons définir deux agents :
Un conservateur de CVE, chargé de trouver sur la page Web les liens vers les CVE qu’il juge les plus importants.
Un analyste de CVE, chargé de consulter les pages Web de ces CVE et d’en extraire les données.
Ouvrez config/agents.yaml et remplacez la définition des agents créée par CrewAI par ce qui suit :
1cve_curator:
2 role: >
3 Senior Security Analyst
4 goal: >
5 Find the links to the top most interesting CVEs reported in {security_vulnerabilities_url}.
6 backstory: >
7 You're a seasoned web scraper with a knack for parsing HTML pages and extracting the most relevant information.
8
9cve_researcher:
10 role: >
11 Senior Security Researcher
12 goal: >
13 Summarize and format the CVE information found by the CVE curator.
14 backstory: >
15 You're a meticulous security researcher with a keen eye for detail. You're known for
16 your ability to turn complex data into clear and concise reports, making
17 it easy for others to understand and act on the information you provide.Tâches
Nous devons ensuite définir les tâches correspondantes :
La première tâche consiste à extraire les liens vers les CVE depuis le répertoire de la base de données des vulnérabilités (la page Web principale qui affiche les résultats de recherche et la liste des vulnérabilités).
La tâche suivante de l’agent analyste de CVE consiste à extraire les données de vulnérabilité depuis la page d’information de chaque CVE.
Ouvrez le fichier config/tasks.yaml et remplacez son contenu, créé par la bibliothèque CrewAI, par ce qui suit :
cve_curation_task:
description: >
Parse the HTML page to find the top most interesting CVEs reported in {security_vulnerabilities_url}.
You need to select 3 CVEs from the page and extract the link to their vulnerability page.
For example, the link to the vulnerability for the package @trpc/server is: https://security.snyk.io/vuln/SNYK-JS-TRPCSERVER-10060256
You should de-prioritize choosing CVEs for malicious packages. Instead, you should prioritize CVEs for popular packages and those that are likely
to have a high impact on the open-source ecosystem.
expected_output: >
A total of 3 CVEs, each formatted as a bullet point in the following markdown format
```
- https://security.snyk.io/vuln/SNYK-JS-TRPCSERVER-10060256
```
agent: cve_curator
cve_research_task:
description: >
For each of the CVE you should extract information by visiting the link to the vulnerability and extracting the information from the page.
For example, the link to the vulnerability for the package @trpc/server is: https://security.snyk.io/vuln/SNYK-JS-TRPCSERVER-10060256
Once you have the link, visit the page and extract the following information:
1) CVE ID (example: CVE-2025-12345)
2) Type of Vulnerability (example: RCE, SQL Injection, etc.)
3) CVE Publication Date (example: 2025-01-01)
4) Link to the CVE vulnerability page (example: https://security.snyk.io/vuln/SNYK-JS-KIBANA-10339388). The link exists as the href attribute of the anchor tag in the HTML page, set on the name of the vulnerability.
5) Package name that was found vulnerable (example: kibana)
expected_output: >
A total of 3 CVEs, each formatted as a bullet point in the following markdown format (strict markdown formatting for example links should not have space between the [] and () chars):
```
**@trpc/server** found vulnerable to CVE-2025-43855 [Uncaught Exception](https://security.snyk.io/vuln/SNYK-JS-TRPCSERVER-10060256), 24 Apr 2025
```
agent: cve_researcherVous remarquerez que les tâches sont formulées avec soin pour que nos agents IA puissent les interpréter et les respecter. Elles comprennent notamment un exemple de résultat attendu et des règles à suivre.
Outils personnalisés
Pour la première tâche et notre premier agent, le conservateur de CVE, nous devons créer notre propre outil en Python. C’est nécessaire, car l’outil CrewAI intégré ScrapeWebsiteTool extrait uniquement le texte d’une page Web. Il ne peut pas analyser davantage le code HTML source pour extraire les éléments d’ancrage (<a href>) contenant les liens vers les données de chaque CVE sur la page.
Pour commencer à créer un outil personnalisé que nos agents pourront utiliser, ouvrez le fichier tools/__init__.py, puis modifiez-le pour exporter un nouvel outil TableScraperTool comme suit :
from .custom_tool import MyCustomTool
from .table_scraper import TableScraperTool
__all__ = ['MyCustomTool', 'TableScraperTool']À noter : MyCustomTool était déjà présent dans la structure de projet créée à partir de l’exemple CrewAI.
Créez ensuite l’outil TableScraperTool : ajoutez un nouveau fichier tools/table_scraper.py, puis insérez-y le code Python suivant :
from typing import List, Dict, Any
from bs4 import BeautifulSoup
import requests
from crewai.tools import BaseTool
class TableScraperTool(BaseTool):
name: str = "table_scraper"
description: str = "Scrapes table data from a webpage, extracting rows, links, and other relevant information"
def _run(self, url: str) -> List[Dict[str, Any]]:
"""
Scrapes table data from the given URL.
Args:
url: The URL to scrape
Returns:
List of dictionaries containing table row data
"""
try:
response = requests.get(url)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
# Find all table rows
rows = soup.find_all('tr', class_='table__row')
table_data = []
for row in rows:
row_data = {}
# Extract severity
severity_elem = row.find('li', class_='severity__item')
if severity_elem:
row_data['severity'] = severity_elem.get('class', [''])[0].replace('severity__item--', '')
# Extract vulnerability title and link
title_link = row.find('a', class_='anchor--underline')
if title_link:
row_data['title'] = title_link.text.strip()
row_data['vuln_link'] = title_link.get('href', '')
# Extract package name and link
package_link = row.find('a', attrs={'data-snyk-test-package-manager': True})
if package_link:
row_data['package_name'] = package_link.text.strip()
row_data['package_link'] = package_link.get('href', '')
# Extract version ranges
version_spans = row.find_all('span', class_='vulns-table__semver')
if version_spans:
row_data['version_ranges'] = [span.text.strip() for span in version_spans]
# Extract package manager and date
package_manager = row.find('span', attrs={'type': True})
if package_manager:
row_data['package_manager'] = package_manager.get('type', '')
row_data['published_date'] = package_manager.get('published', '')
if row_data: # Only add if we found some data
table_data.append(row_data)
return table_data
except Exception as e:
return [{"error": f"Failed to scrape table data: {str(e)}"}]
async def _arun(self, url: str) -> List[Dict[str, Any]]:
"""Async implementation of the tool"""
return self._run(url)Enfin, nous devons ajouter la bibliothèque Python BeautifulSoup au projet. Modifiez donc la liste dependencies dans myproject.toml pour l’inclure comme suit :
dependencies = [
...
"beautifulsoup4>=4.12.0"Appliquez ensuite les modifications avec la commande suivante :
uv pip install -e .Fichier d’exécution principal de CrewAI
Intéressons-nous maintenant au fichier principal crew.py, que vous trouverez dans le répertoire src/security_news_summary ou dans un autre répertoire où vous avez créé la structure du projet CrewAI.
Modifiez d’abord les instructions d’importation du fichier pour y inclure notre outil personnalisé TableScraperTool :
from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai_tools import ScrapeWebsiteTool
from typing import List
from .tools import TableScraperToolFaites ensuite défiler le fichier jusqu’aux fonctions annotées pour les agents (annotation @agent) et les tâches (annotation @task), puis modifiez-les pour qu’elles correspondent aux agents et tâches que nous venons de définir :
@agent
def cve_curator(self) -> Agent:
return Agent(
config=self.agents_config['cve_curator'], # type: ignore[index]
verbose=True,
tools=[ScrapeWebsiteTool(), TableScraperTool()]
)
@agent
def cve_researcher(self) -> Agent:
return Agent(
config=self.agents_config['cve_researcher'], # type: ignore[index]
verbose=True,
tools=[ScrapeWebsiteTool()]
)
# To learn more about structured task outputs,
# task dependencies, and task callbacks, check out the documentation:
# https://docs.crewai.com/concepts/tasks#overview-of-a-task
@task
def cve_curation_task(self) -> Task:
return Task(
config=self.tasks_config['cve_curation_task'], # type: ignore[index]
output_file='cves.md'
)
@task
def cve_research_task(self) -> Task:
return Task(
config=self.tasks_config['cve_research_task'], # type: ignore[index]
output_file='cves.md'
)Exécuter des agents IA avec CrewAI
Voilà, c’est prêt. Nous pouvons maintenant lancer nos agents IA pour sélectionner de nouvelles vulnérabilités de sécurité à partir de la Snyk Vulnerability Database.
Il ne nous reste plus qu’à lancer les agents CrewAI depuis le terminal avec cette commande :
crewai runLes agents IA se mettent alors au travail :

Les tâches s’affichent au fil de leur progression :

À propos de la sécurité de l’IA et des workflows agentiques
Créer des agents IA a quelque chose de magique. Quand tout fonctionne, les résultats sont étonnamment bons, et la bibliothèque CrewAI, qui orchestre les agents, est très simple à utiliser.
Les workflows de codage avec l’IA et les agents évoluent très rapidement. Il est donc essentiel de rester vigilant quant à la fiabilité de l’IA et de mettre en place des garde-fous de sécurité pour éviter les risques et les failles, comme le déploiement non sécurisé de serveurs MCP, les attaques par injection de prompt et les autres vecteurs de vulnérabilité liés à l’IA.
Voici les ressources que je vous recommande :
Consultez les garde-fous de sécurité pour le code IA de Snyk
Sécuriser le codage avec l’IA avec Snyk (et les serveurs MCP)
Comprendre les attaques par injection de prompt : techniques, défis et risques.
Sécurisez le développement avec l’IA dès le départ
Découvrez comment intégrer la sécurité à chaque étape de votre workflow de développement avec l’IA, grâce aux conseils pratiques de nos experts.