8 min de lecture

Bugs d’encodage d’URL : testez les entrées API de l’agent avant les appels

Les bugs d’encodage d’URL peuvent envoyer un agent vers la mauvaise route API ou modifier les données d’une requête. Testez d’abord les chemins, requêtes, séquences percent et caractères spéciaux.

Bugs d’encodage d’URL : testez les entrées API de l’agent avant les appels

Une URL n’est pas une chaîne inoffensive. C’est une instruction structurée dont les délimiteurs déterminent l’hôte, la route, les noms de paramètres et leurs valeurs. Si un agent combine incorrectement un texte fourni par l’utilisateur avec une URL, il peut appeler un autre point de terminaison que celui examiné par le développeur.

J’ai vu des équipes approuver une requête qui ressemblait à GET /records/alice dans le journal d’un outil, avant de passer l’après-midi à découvrir que le serveur avait reçu une route avec une barre oblique supplémentaire, un paramètre de requête en double ou une séquence de traversée décodée. L’agent n’avait pas besoin d’un exploit exotique. Un texte ordinaire comme a+b, %2F, &admin=true ou un nom dans un alphabet non latin suffisait.

Les bugs d’encodage d’URL sont faciles à minimiser, car un client HTTP « gère souvent l’encodage ». Il gère une partie de la sérialisation, selon sa propre API et ses valeurs par défaut. Il ne peut pas décider si une valeur utilisateur appartient à un segment de chemin, à une valeur de requête, au corps d’un formulaire ou à aucun de ces endroits. Cette décision doit figurer dans la définition de l’action et dans ses tests.

C’est la cible de la requête, pas la chaîne visible, qui détermine l’appel

Une requête peut changer de sens chaque fois qu’un logiciel analyse ou reconstruit son URL. La séquence de caractères produite par l’agent n’est que le début. Votre bibliothèque cliente peut la normaliser, un proxy inverse peut la réécrire et le framework de l’application peut la décoder avant la correspondance de route ou la liaison des paramètres.

La RFC 3986 divise un URI en composants : schéma, autorité, chemin, requête et fragment. Dans un chemin, / est un délimiteur. Dans une requête, & et = prennent un sens selon les conventions courantes, même si la RFC 3986 ne définit pas de grammaire universelle pour les requêtes. Cette distinction explique la plupart des problèmes que l’on désigne vaguement comme des « problèmes d’encodage ».

Prenons une action destinée à récupérer un projet :

GET https://api.example.test/projects/{project_id}

Si project_id vaut north/ops, ces deux cibles sont différentes :

/projects/north/ops
/projects/north%2Fops

La première contient deux segments après projects. La seconde tente de transporter une barre oblique littérale dans un seul segment. La conservation de cette forme dépend de toute la chaîne entre le client et l’application. Certains environnements décodent %2F avant la correspondance et la transforment en première forme. D’autres la refusent. Un test client qui vérifie seulement que « l’URL a été encodée » ne prouve presque rien.

Le même piège existe dans les requêtes. Une action qui doit rechercher une expression littérale ne devrait pas construire ceci :

/search?q=USER_TEXT

en remplaçant USER_TEXT par du texte brut. Avec red&limit=500, la cible finale peut devenir :

/search?q=red&limit=500

L’application voit alors deux paramètres. Si le code crée un objet de requête et fournit red&limit=500 comme valeur de q, il devrait produire :

/search?q=red%26limit%3D500

C’est cette limite concrète qu’il faut tester : un champ sémantique en entrée, une cible exacte en sortie, puis le même champ sémantique analysé à destination.

Ne testez pas seulement avec des lettres et des chiffres. Ces valeurs masquent précisément les bugs que les agents révèlent. Un agent reçoit des tickets d’assistance, des titres d’incidents, des noms de branches, des chemins de fichiers, des URL copiées et du texte libre. Les entrées réelles contiennent des délimiteurs.

Un paramètre de chemin est un segment, pas une URL incomplète

Traitez un paramètre de chemin comme un seul segment, sauf si le contrat de l’API indique explicitement qu’il accepte un chemin. Cette règle élimine une quantité surprenante d’ambiguïtés.

Les développeurs concatènent souvent les chemins parce que le résultat semble lisible :

const target = base + "/projects/" + projectId + "/builds";

Ce code n’attribue aucune signification propre au composant projectId. Si la valeur contient /, ?, # ou %, le résultat dépend de ce que le code suivant fait avec target. Cela invite aussi à une deuxième erreur : quelqu’un voit une valeur encodée dans un journal, applique de nouveau encodeURIComponent « par sécurité » et produit un identifiant différent.

Construisez les segments comme des données, encodez chaque segment une seule fois et ne joignez que les séparateurs appartenant à la route. En JavaScript, ce petit utilitaire rend le contrat visible :

function pathSegment(value) {
  if (typeof value !== "string" || value.length === 0) {
    throw new Error("project id must be a nonempty string");
  }
  return encodeURIComponent(value);
}

const path = "/projects/" + pathSegment(projectId) + "/builds";

encodeURIComponent convient ici, car il encode /, ?, #, & et = qui pourraient autrement modifier le chemin, commencer une requête ou un fragment. Il laisse toutefois quelques caractères RFC 3986 non échappés, dont les apostrophes et les parenthèses. Cela ne change généralement pas la structure du chemin, mais un contrat d’API strict peut exiger un encodeur plus précis. Décidez-en à partir de la spécification de l’API, pas par habitude.

N’utilisez pas encodeURI pour un segment unique. Cette fonction conserve les délimiteurs URI, car elle attend un URI complet. Si vous lui transmettez north/ops, la barre oblique reste présente et la route change. Le nom de la fonction semble approprié, mais son périmètre ne l’est pas.

Un chemin peut légitimement contenir plusieurs segments, par exemple si une API définit /{owner}/{repository}. Modélisez alors deux champs, et non une chaîne libre resourcePath. Si votre point de terminaison a réellement besoin d’un identifiant opaque pouvant contenir des barres obliques, envisagez de le placer dans un paramètre de requête ou dans un corps JSON. Les API qui forcent du texte opaque à passer par les couches de routage obligent chacun à deviner le comportement des barres encodées.

L’encodage côté client ne peut pas non plus corriger certaines décisions de routage. De nombreux proxies et frameworks normalisent les segments . et .., regroupent les barres obliques répétées ou refusent les séparateurs encodés. Posez au responsable du point de terminaison une question directe : la correspondance de route a-t-elle lieu avant ou après le décodage percent ? Testez ensuite la route déployée, proxy compris. La documentation d’un framework exécuté seul sur le poste d’un développeur ne répond pas à cette question.

Les chaînes de requête ont besoin d’une grammaire déclarée

Une chaîne de requête n’est pas un bloc unique à échapper. C’est un ensemble de champs dont la grammaire appartient à l’API. Il faut décider à l’avance du comportement des noms répétés, des valeurs vides, des tableaux, des booléens, des espaces et des doublons.

Les API orientées navigateur et la norme WHATWG utilisent une sérialisation de type formulaire pour URLSearchParams. Dans cette convention, un espace devient souvent + et un plus littéral devient %2B. De nombreux analyseurs serveur utilisent la même convention. La RFC 3986 ne dit toutefois pas que + signifie un espace dans un URI générique. Ces deux faits comptent lorsqu’un composant utilise un analyseur générique et un autre un analyseur de formulaire.

Utilisez un générateur de requête plutôt que des modèles de chaînes :

const query = new URLSearchParams();
query.set("q", userText);
query.set("include_archived", "false");
for (const label of labels) query.append("label", label);

const url = "https://api.example.test/search?" + query.toString();

Pour userText = "C++ & systems", l’écriture exacte peut être q=C%2B%2B+%26+systems. Un serveur qui applique le décodage des formulaires doit retrouver C++ & systems. Votre test de régression doit vérifier la valeur sémantique attendue par l’API, et non imposer à toutes les bibliothèques d’utiliser %20 pour les espaces. %20 et + peuvent tous deux représenter un espace selon les conventions de requête rencontrées ; un plus littéral doit rester un plus après l’analyse.

Les champs répétés exigent une décision explicite. Ces trois contrats sont différents :

?label=bug&label=security
?label=bug,security
?label=["bug","security"]

Le premier utilise un nom répété. Le deuxième est une valeur contenant une virgule, sauf indication contraire de l’API. Le troisième ressemble à du JSON, mais n’est pas du JSON tant qu’un serveur ne l’analyse pas volontairement. Ne dites pas à un agent de « passer les labels dans l’URL » sans préciser le format. Donnez à l’action un argument tableau et faites-lui utiliser la seule forme acceptée par le point de terminaison.

Les paramètres scalaires en double constituent un autre échec discret. Une requête ?role=user&role=admin peut produire la première valeur, la dernière, un tableau ou une erreur selon le framework. Une vérification de sécurité qui lit la première valeur alors qu’un service en aval lit la dernière crée une décision divergente. Refusez les doublons pour les champs qui ne doivent apparaître qu’une fois, dès le premier composant que vous contrôlez.

Les fragments méritent aussi une mention. #section ne quitte généralement jamais le client comme partie d’une requête HTTP. Si une donnée utilisateur brute contient #, elle peut retirer tout ce qui suit d’un objet URL avant l’envoi. Encodez ce caractère dans une valeur de chemin ou de requête lorsqu’il s’agit d’une donnée. Ne vous fiez pas au journal de la chaîne source pour savoir ce qui a atteint le serveur.

Les signes percent et l’ordre des décodages créent des identifiants différents

Décodez les séquences percent une seule fois, à une frontière définie. Si deux composants décodent la même entrée, une valeur apparemment inoffensive peut devenir un délimiteur après avoir passé la première vérification.

Prenez le texte %252F. Un premier décodage donne %2F. Un second donne /. Cela compte lorsque la validation intervient entre ces deux opérations. Une passerelle peut refuser / dans un identifiant et accepter %252F, puis une application en amont peut décoder une deuxième fois et découper la route. Le même phénomène s’applique à %252e, qui devient %2e, puis ..

Distinguez trois valeurs dans les discussions de conception et dans les tests :

  1. L’écriture brute sur le réseau, comme %252F.
  2. La valeur après un décodage percent, comme %2F.
  3. La valeur de l’application après tous les analyseurs et toutes les réécritures, comme /.

Les équipes appellent souvent les trois « l’URL ». Ce vocabulaire flou provoque de mauvaises revues, car on compare des étapes différentes sans s’en rendre compte.

La RFC 3986 conseille aux producteurs d’URI de ne pas encoder ou décoder plusieurs fois la même chaîne. C’est un bon principe, mais ce n’est pas un plan d’implémentation. Définissez la frontière à laquelle votre sérialiseur d’action accepte des chaînes applicatives décodées, puis celle à laquelle le serveur accepte les octets bruts de la requête. Tout ce qui se trouve entre ces frontières doit conserver l’échappement ou refuser les formes qu’il ne peut pas préserver.

N’acceptez pas des entrées déjà encodées par commodité. Une consigne demandant à un agent de « fournir un identifiant de projet encodé en URL » l’oblige à deviner si %2F est une donnée ou une instruction. La couche suivante ne peut pas savoir si elle doit conserver le signe percent ou l’encoder en %25. Acceptez des champs en texte clair, encodez-les une seule fois dans la couche d’action et ne refusez les séquences percent mal formées que là où les URL brutes sont réellement acceptées.

L’Unicode ajoute une frontière supplémentaire. Un client URL transforme normalement le texte en octets UTF-8 et encode les octets qui ne peuvent pas apparaître directement dans le composant choisi. Les frameworks serveur peuvent normaliser l’Unicode différemment avant de rechercher un utilisateur ou une ressource. Gardez les identifiants sous une forme canonique au niveau de l’application si votre domaine l’exige. L’échappement transporte des octets ; il ne décide pas si deux chaînes visuellement proches désignent le même compte.

Testez toute la route avec des entrées adversariales mais ordinaires

Séparez l’approbation de l’analyse des URL
Sallyport sépare l’approbation des identifiants de la validation structurée des requêtes dans votre couche d’action.

Un test d’encodage utile observe deux choses : la cible de requête émise par le client et les valeurs analysées par le destinataire. Si vous ne testez qu’un côté, une réécriture de proxy ou un décodeur de framework peut encore modifier le sens au milieu.

Commencez par un gestionnaire echo contrôlé dans votre environnement de test. Il doit enregistrer la cible brute lorsque le runtime du serveur l’expose, puis renvoyer le chemin et les champs de requête analysés. N’utilisez pas d’identifiants sur ce point de terminaison. Son rôle est d’exposer la sérialisation, pas d’authentifier qui que ce soit.

Cet exemple de gestionnaire Node illustre la forme de la réponse :

import http from "node:http";

http.createServer((req, res) => {
  const url = new URL(req.url, "http://local.test");
  const pairs = [...url.searchParams.entries()];
  res.setHeader("content-type", "application/json");
  res.end(JSON.stringify({
    requestTarget: req.url,
    pathname: url.pathname,
    queryPairs: pairs
  }, null, 2));
}).listen(8787);

Envoyez-lui des cas connus et conservez le résultat attendu. Par exemple, un générateur recevant C++ & systems doit produire une sortie contenant une seule paire q, dont la valeur analysée est exactement C++ & systems. Une requête construite à la main se révèle souvent en renvoyant deux paires ou en transformant les signes plus en espaces.

{
  "requestTarget": "/search?q=C%2B%2B+%26+systems",
  "pathname": "/search",
  "queryPairs": [["q", "C++ & systems"]]
}

Votre suite doit couvrir une matrice réduite, plutôt que des dizaines de chaînes aléatoires :

  • espace, plus littéral, signe percent, esperluette, signe égal, point d’interrogation et dièse ;
  • barre oblique et barre oblique encodée dans un identifiant censé rester un seul segment ;
  • chaînes vides, champs facultatifs absents et noms de requête répétés ;
  • valeur Unicode et valeur dont les séquences percent ressemblent à un second passage de décodage ;
  • URL complète collée dans un champ qui attend un identifiant.

Utilisez des tests basés sur les propriétés si votre équipe les pratique déjà, mais ne cachez pas les cas nommés derrière des exemples générés. Ils expliquent pourquoi la frontière existe. Lorsqu’une régression survient, encoded slash stays inside project_id est beaucoup plus utile qu’un numéro de graine.

Exécutez les mêmes tests d’intégration sur le chemin utilisé par le trafic de production. Un test direct contre le processus de l’application ne dira pas si un proxy refuse %2F, réécrit les barres obliques répétées ou choisit une autre valeur en présence d’un paramètre répété. Si le point d’entrée de production ne peut pas être inclus localement, utilisez une route de préproduction avec la même configuration et faites de ce test une vérification de déploiement.

Donnez aux agents des arguments structurés, pas la liberté de construire des URL

Un agent doit choisir une action et fournir des arguments typés. L’implémentation de l’action doit choisir la méthode HTTP, l’origine autorisée, le modèle de route, la grammaire de requête, les en-têtes et l’encodage. Permettre à l’agent de transmettre une URL complète réunit tous ces contrôles dans une seule chaîne ambiguë.

Un contrat d’action étroit peut ressembler à ceci :

{
  "name": "get_project_builds",
  "input": {
    "project_id": "north/ops",
    "branch": "release+candidate",
    "limit": 25
  }
}

Le code de l’action doit valider project_id comme identifiant, l’encoder comme un seul segment de chemin, placer branch dans un générateur de requête, vérifier que limit est un entier dans la plage autorisée par l’API et construire l’URL à partir d’une origine fixe. Le modèle n’a jamais besoin de voir un jeton bearer ni de décider où placer une esperluette.

Cette séparation évite aussi la confusion d’origine. Une chaîne commençant par https://other.example n’a rien à faire dans un champ d’identifiant. Si une action doit réellement récupérer une URL fournie par l’utilisateur, faites-en une action distincte avec une liste d’autorisation, des règles DNS et de redirection et une raison clairement documentée. Ne dissimulez pas une capacité de récupération arbitraire derrière un champ nommé callback ou file.

Soyez prudents avec les API qui acceptent des langages de filtrage dans les paramètres de requête. Un champ comme filter=status:open AND owner:me possède deux grammaires : la sérialisation de la requête URL et le langage de filtrage. L’encodage URL conserve le filtre dans une seule valeur de requête, mais ne rend pas le filtre sûr. Analysez ou limitez séparément ce langage interne, ou proposez des champs de filtre typés.

Évitez de placer des secrets dans les URL. Les chaînes de requête peuvent se retrouver dans les journaux d’accès, l’historique du navigateur, la télémétrie et les rapports d’erreur. Les identifiants doivent utiliser le mécanisme d’autorisation attendu par l’API. Encoder un jeton API ne rend pas sa présence dans une requête sûre.

L’approbation est utile, mais elle ne répare pas une requête mal formée

Gardez les identifiants hors des agents
Sallyport exécute lui-même les actions HTTP et SSH authentifiées et renvoie les résultats sans exposer les clés.

L’autorisation humaine et la sérialisation correcte répondent à deux problèmes différents. Une approbation peut confirmer qu’un processus d’agent reconnu peut utiliser un identifiant. Elle ne révèle pas si une séquence percent deviendra une barre oblique dans un routeur en aval, ni si un paramètre dupliqué modifiera les privilèges après analyse.

Cette distinction compte lorsque quelqu’un affirme que les invites ou les cartes d’approbation rendent inutile une construction stricte des requêtes. Ce n’est pas le cas. Une personne examinant https://api.example.test/projects/%252Fadmin devrait simuler mentalement chaque décodeur de la route pour comprendre le résultat. Ce n’est pas un contrôle de sécurité raisonnable, surtout lorsqu’un agent peut effectuer de nombreux appels pendant une session.

Placez les contrôles déterministes avant l’approbation :

  • acceptez des champs structurés plutôt qu’une cible préassemblée ;
  • fixez l’origine, la méthode et le modèle de route dans la définition de l’action ;
  • sérialisez chaque segment de chemin et chaque valeur de requête une seule fois ;
  • refusez les champs en double ou mal formés que le point de terminaison ne définit pas ;
  • testez la cible finale sur le chemin de requête déployé.

Sallyport peut garder les identifiants hors d’un agent compatible MCP et demander une autorisation pour un processus d’agent ou pour chaque utilisation d’un identifiant sélectionné. Ce contrôle humain fonctionne mieux lorsque la couche d’action produit déjà une requête dépourvue d’ambiguïté.

Les journaux ont eux aussi besoin de deux niveaux de détail. Enregistrez l’action approuvée et ses arguments sûrs, puis conservez une représentation expurgée de la cible réellement envoyée et du résultat HTTP. Si un service possède un champ de requête sensible, masquez sa valeur tout en gardant son nom et une forme suffisante pour diagnostiquer une duplication accidentelle. Ne consignez jamais les en-têtes d’autorisation simplement parce qu’une requête a échoué.

La normalisation des routes peut défaire un client correct

Placez les appels HTTP sous contrôle
Les agents se connectent via le shim sp mcp inclus, tandis que Sallyport gère les appels HTTP authentifiés.

Une requête parfaitement sérialisée peut tout de même changer aux frontières de l’infrastructure. Proxies, répartiteurs de charge, pare-feu applicatifs et serveurs d’application ont chacun leur comportement concernant les barres obliques répétées, les segments pointés, les séparateurs encodés et les séquences invalides. Il faut un contrat de route pour toute la chaîne.

Prenons un point de terminaison dont le client envoie ce chemin :

/files/reports%2F2025%2Fnotes

Si l’API attend un identifiant de fichier opaque, le paramètre applicatif souhaité est reports/2025/notes. Mais un proxy qui décode avant de transmettre peut envoyer /files/reports/2025/notes. Un routeur configuré pour /files/:id peut le refuser. Un autre peut faire correspondre /files/:folder/:year/:name et appeler un autre gestionnaire. Aucun de ces résultats ne prouve que l’encodeur client a échoué.

Prenez une décision pour chaque route sensible. Vous pouvez refuser les barres obliques encodées à la périphérie et documenter que les identifiants ne peuvent pas en contenir. Vous pouvez les préserver jusqu’au gestionnaire et tester cette propriété. Vous pouvez aussi repenser le point de terminaison afin que les données opaques vivent hors du chemin. Ce qu’il ne faut pas faire, c’est laisser le comportement dépendre de valeurs par défaut propres à une version et appeler cela une frontière de sécurité.

Surveillez également les redirections. Les clients HTTP peuvent suivre automatiquement les redirections, et une URL redirigée peut contenir un chemin ou une requête normalisés différemment. Pour les actions utilisant des identifiants, définissez si les redirections sont autorisées, si l’origine de destination doit correspondre et si les en-têtes d’autorisation doivent être supprimés en cas de changement d’origine. Ce sujet est distinct de l’encodage percent, mais les bugs d’URL et les règles de redirection se rencontrent souvent dans le même code.

Si vous exploitez plusieurs services, testez volontairement leurs divergences. Envoyez le même chemin encodé à travers la périphérie puis directement à l’application dans un environnement hors production. Si leurs valeurs de chemin analysées diffèrent, corrigez le problème avant d’autoriser un agent à accéder à la route. Un analyseur divergent est un problème opérationnel, même si aucun attaquant ne l’exploite.

Une suite de régression doit préserver le sens voulu

Le but des tests d’URL n’est pas d’imposer une seule écriture d’échappement. Il est de préserver la relation entre les arguments de l’action et le sens côté serveur d’une requête, malgré l’évolution des bibliothèques et de l’infrastructure.

Écrivez des assertions à trois niveaux. Les tests unitaires doivent vérifier qu’un encodeur de segment transforme a/b en un segment encodé unique et que la sérialisation des requêtes conserve & dans une valeur. Les tests d’action doivent capturer la méthode, l’origine, le chemin et les paires de requête exacts envoyés à un gestionnaire echo. Les tests d’intégration doivent traverser une périphérie proche de la production et vérifier que le gestionnaire reçoit la route et les paramètres attendus.

Lorsque le contrat d’une API est vague, notez l’ambiguïté et éliminez-la. « Prend en charge le texte de recherche dans l’URL » n’est pas un contrat. Indiquez si q vide est accepté, si q=a+b signifie un plus ou un espace, si les valeurs tag répétées sont autorisées et si %2F est permis dans les identifiants. Ces détails cessent d’être accessoires dès qu’un agent peut générer des appels à partir de texte humain arbitraire.

Ne masquez pas un test défaillant en décodant l’entrée plus tôt. Un décodage précoce donne souvent une apparence normale au cas tout en déplaçant l’ambiguïté vers une couche moins visible. Conservez le texte brut comme donnée jusqu’à ce que le sérialiseur propre au composant le traite. Examinez ensuite ce que le destinataire a réellement analysé.

Le journal Activity de Sallyport facilite la comparaison entre l’appel approuvé par un agent et le résultat renvoyé, tandis que sa chaîne d’audit peut être vérifiée hors ligne avec sp audit verify. Utilisez cette trace pour enquêter sur une divergence, pas pour décider à la place de votre point de terminaison ce qu’il accepte.

Le premier test que j’ajouterais est volontairement banal : un identifiant contenant /, une valeur de requête contenant + et &, et un signe percent qui doit rester littéral. Si votre action ne peut pas préciser exactement ce que reçoit le serveur pour ces entrées, elle n’est pas prête à accepter du texte utilisateur provenant d’un agent.

FAQ

Comment vérifier qu’un client API a correctement encodé une URL ?

Testez les octets qui quittent le client, l’URL reçue par votre serveur ou votre proxy, puis les valeurs de chemin et de requête utilisées par l’application. Ces éléments peuvent différer, car la bibliothèque cliente sérialise l’entrée, un intermédiaire la normalise et un framework la décode. Un test qui vérifie uniquement le statut HTTP final ne révèle pas le désaccord à l’origine du problème.

Puis-je utiliser la même fonction d’encodage pour les chemins et les chaînes de requête ?

Non. Un segment de chemin identifie une partie de la hiérarchie d’une ressource, tandis qu’une requête contient des paires de noms et de valeurs. Encoder une barre oblique dans un chemin n’a pas les mêmes conséquences que l’encoder dans une valeur de requête. Une seule fonction d’échappement générique constitue donc un mauvais contrat.

Pourquoi un signe plus devient-il un espace dans une chaîne de requête API ?

Un signe plus n’a pas de signification particulière dans la syntaxe URI générique décrite par la RFC 3986. Pourtant, de nombreux analyseurs de requêtes inspirés des formulaires décodent le signe plus comme un espace, conformément aux conventions application/x-www-form-urlencoded. Traitez le signe plus comme une donnée et encodez-le en %2B lorsque sa valeur littérale compte.

Faut-il encoder en %2F une barre oblique présente dans un paramètre de chemin ?

En général, encodez en %2F une barre oblique qui appartient aux données utilisateur avant de l’insérer dans un segment de chemin unique. Vérifiez ensuite que chaque composant du trajet la conserve au lieu de la décoder et de couper la route. Certains serveurs refusent les barres obliques encodées. Un identifiant opaque placé dans la requête ou le corps peut alors constituer une conception plus sûre.

Les valeurs d’URL encodées deux fois sont-elles dangereuses ?

Cela peut être dangereux. Un premier décodeur peut transformer %252F en %2F, puis un second en barre oblique et modifier le routage ou la validation. Refusez les séquences percent inattendues après un décodage unique et testez l’ensemble du trajet de la requête au lieu de faire confiance à un seul composant.

Comment un agent doit-il envoyer des tableaux dans une chaîne de requête ?

?tag=a&tag=b est généralement un paramètre répété, tandis que ?tag=a,b est une valeur contenant une virgule, sauf indication contraire de l’API. Les agents doivent recevoir la représentation déclarée par l’API, et les tests doivent vérifier comment les valeurs vides, les noms répétés et l’ordre arrivent au serveur.

Est-il prudent de laisser un agent IA construire une URL complète à partir de données utilisateur ?

Placez le texte non fiable dans des arguments structurés d’outil, puis laissez la couche d’action sérialiser chaque champ selon sa destination. Ne laissez pas un agent assembler une URL complète par concaténation de chaînes. Cette séparation permet de refuser une origine étrangère, un composant user-info ou un fragment inattendu avant l’exécution de la requête.

Que faut-il consigner pour diagnostiquer les erreurs d’encodage d’URL ?

Un journal qui affiche une URL décodée peut masquer les octets encodés qui ont modifié la requête. Enregistrez une représentation sûre et expurgée de la cible finale, ainsi que les champs de chemin et de requête analysés. Ne placez jamais des identifiants dans une URL pour faciliter le débogage.

Une approbation humaine peut-elle empêcher les attaques liées à l’encodage d’URL ?

Une approbation confirme qu’un processus peut effectuer un appel. Elle ne permet pas de savoir si %252e%252e%252f sera décodé deux fois par un proxy et deviendra un autre chemin en aval. La construction de la requête nécessite une validation déterministe avant la frontière d’approbation.

Quels caractères spéciaux inclure dans les tests de régression d’encodage d’URL ?

Utilisez un point de terminaison echo local ou un service de test contrôlé et incluez les espaces, les signes plus, les signes percent, les délimiteurs encodés, l’Unicode, les noms de requête répétés et les valeurs vides. Comparez la cible brute avec les champs analysés par le serveur, puis conservez ces cas dans les tests de régression lorsque la bibliothèque cliente, le proxy ou le framework API évolue.

Sallyport

Sallyport exécute les appels d'API et les commandes SSH à la place de votre agent IA. Les clés restent dans un coffre-fort local sur votre Mac ; vous approuvez chaque exécution et chaque action est consignée dans un journal scellé.

© 2026 Sallyport · Open source sous Apache-2.0 · Oleg Sotnikov