You describe what you want from AI in a few sentences. The Advisor asks a couple of clarifying questions, then produces the prompt you should actually use, a comparison of doing it directly with Claude versus building it on AWS, a process map, an entry-level business analysis, and — if you ask — a CloudFormation template. Vous décrivez en quelques phrases ce que vous attendez de l'IA. L'Advisor pose deux ou trois questions de clarification, puis produit le prompt à utiliser réellement, une comparaison entre passer directement par Claude ou bâtir sur AWS, une carte de processus, une analyse d'affaires de premier niveau et, sur demande, un gabarit CloudFormation.
It is free to use, it runs on my own AWS account, and its input box invites strangers to type instructions into a language model. That last sentence is the whole security problem in miniature. Il est gratuit, il tourne sur mon compte AWS, et sa boîte de saisie invite des inconnus à écrire des instructions destinées à un modèle de langage. Cette dernière phrase résume tout le problème de sécurité.
The request pathLe chemin d'une requête
One Lambda, one model, one round trip. The model is Claude Haiku 4.5, reached through a cross-region inference profile, and every call uses the Converse API with toolChoice: any. Forcing a tool call is not about giving the model tools — it has none. It is the cheapest way to get a typed result: the tool schema becomes the output contract, so the answer arrives as structured JSON rather than prose I would have to parse.
Un seul Lambda, un seul modèle, un seul aller-retour. Le modèle est Claude Haiku 4.5, joint par un profil d'inférence interrégional, et chaque appel passe par l'API Converse avec toolChoice: any. Forcer l'appel d'outil ne sert pas à donner des outils au modèle — il n'en a aucun. C'est la façon la moins chère d'obtenir un résultat typé : le schéma de l'outil devient le contrat de sortie, donc la réponse arrive en JSON structuré plutôt qu'en prose à analyser.
Thirty seconds decides everything elseTrente secondes décident du reste
An API Gateway HTTP API times out at 30 seconds and cannot be raised. That single limit sets every other number in the system. I measured the model's throughput at roughly 4.6 seconds of overhead plus 3 milliseconds per output token, which makes the arithmetic blunt: a phase that needs 3,400 tokens is already near 15 seconds, and anything past that risks the client seeing a timeout instead of an answer. Une API HTTP d'API Gateway expire à 30 secondes, sans possibilité d'augmenter la limite. Cette seule contrainte fixe tous les autres chiffres du système. J'ai mesuré le débit du modèle à environ 4,6 secondes de surcharge plus 3 millisecondes par jeton produit, ce qui rend le calcul brutal : une phase qui demande 3 400 jetons frôle déjà les 15 secondes, et au-delà le client risque de voir une expiration plutôt qu'une réponse.
So the work is split into phases with their own budgets rather than one long generation. Le travail est donc découpé en phases avec leur propre budget, plutôt qu'en une seule longue génération.
MAX_TOKENS = {"clarify": 700, "generate_minimal": 1200, "generate_full": 2400,
"document": 2300, "iac": 3400, "iac_compact": 1400}
The CloudFormation phase is the expensive one, and it kept getting cut off mid-template. Raising the cap helped; what actually fixed it was telling the model to stop writing working Lambda handlers inline and to defer resources it could not fit into a "not included yet" list. A template that admits what it left out is more useful than one that silently stops. La phase CloudFormation est la plus coûteuse, et elle se faisait couper en plein gabarit. Augmenter le plafond a aidé ; ce qui a réellement réglé le problème, c'est d'exiger du modèle qu'il cesse d'écrire des gestionnaires Lambda complets en ligne et qu'il reporte dans une liste « pas encore inclus » ce qu'il ne pouvait pas caser. Un gabarit qui avoue ce qu'il a omis vaut mieux qu'un gabarit qui s'arrête en silence.
Guardrails, and what they missedLes garde-fous, et ce qu'ils ont raté
There is a Bedrock guardrail in front of the model: four denied topics, content filters, and fourteen categories of personal information set to be masked. Getting it useful took three corrections, each of which was a lesson about the difference between a guardrail on paper and one in production. Un garde-fou Bedrock se trouve devant le modèle : quatre sujets interdits, des filtres de contenu et quatorze catégories de renseignements personnels à masquer. Le rendre utile a exigé trois corrections, chacune révélant l'écart entre un garde-fou sur papier et un garde-fou en production.
It refused everything on day oneIl refusait tout dès le premier jour
The first deploy blocked every request. The cause was almost funny: my own phase instructions — the block of rules telling the model what to produce — read to the prompt-attack filter exactly like an injection attempt, because structurally that is what they are. The fix was to tag only the visitor's own words with guardContent and leave my instructions untagged, so the filter judges the input rather than the scaffolding around it.
Le premier déploiement bloquait toutes les requêtes. La cause prêtait presque à rire : mes propres consignes de phase — le bloc de règles qui dit au modèle quoi produire — ressemblaient, pour le filtre d'injection, à une tentative d'attaque, parce que structurellement c'en est une. La correction : n'étiqueter avec guardContent que les mots du visiteur et laisser mes consignes hors étiquette, pour que le filtre juge l'entrée et non l'échafaudage autour.
The filter was set too high for this shape of inputLe filtre était trop élevé pour ce type d'entrée
Even after that, legitimate briefs were being refused. A tool whose entire purpose is to accept instructions and turn them into better instructions will always look suspicious to a filter tuned for chat. I lowered the prompt-attack threshold deliberately, accepting a weaker filter because the layers behind it do not depend on it. Même après cela, des demandes légitimes étaient refusées. Un outil dont la raison d'être est d'accepter des instructions pour les transformer en meilleures instructions paraîtra toujours suspect à un filtre calibré pour la conversation. J'ai abaissé le seuil délibérément, en acceptant un filtre plus faible parce que les couches derrière lui n'en dépendent pas.
Masking did not work the way I assumedLe masquage ne fonctionnait pas comme je le croyais
I believed personal information typed into the box was being masked before it reached the model. It was not. Guardrails apply anonymisation on the output path, not the input one — the trace showed zero masking units applied, and the only reason no name appeared in a result was that the model happened not to repeat it. The tool now screens input by calling ApplyGuardrail with the source set to output purely to obtain the spans it would have masked, then redacts them itself before inference. The API is being used against the grain, and that is worth saying plainly rather than hiding behind a diagram.
Je croyais que les renseignements personnels saisis dans la boîte étaient masqués avant d'atteindre le modèle. Ils ne l'étaient pas. Les garde-fous appliquent l'anonymisation sur le chemin de sortie, pas d'entrée — la trace affichait zéro unité de masquage, et si aucun nom n'apparaissait dans un résultat, c'est seulement que le modèle ne l'avait pas répété. L'outil filtre maintenant l'entrée en appelant ApplyGuardrail avec la source réglée sur la sortie, uniquement pour obtenir les segments qu'il aurait masqués, puis les caviarde lui-même avant l'inférence. L'API est utilisée à contresens, et il vaut mieux le dire franchement que de le cacher derrière un schéma.
The layer that actually mattersLa couche qui compte vraiment
The honest summary is that prompt injection is not primarily a prompt problem. Suppose someone talks the model into wanting my data. There is no retrieval step to poison, no tool to call, and the execution role can reach exactly one DynamoDB table, one inference profile, and PutObject on one bucket. My account holds several other tables, including live booking records; the Advisor's Lambda cannot read any of them, and no wording in the input box changes that.
Le constat honnête, c'est que l'injection de prompt n'est pas d'abord un problème de prompt. Supposons qu'on convainque le modèle de vouloir mes données. Il n'y a aucune étape de récupération à empoisonner, aucun outil à appeler, et le rôle d'exécution atteint exactement une table DynamoDB, un profil d'inférence et PutObject sur un seul seau. Mon compte contient plusieurs autres tables, dont des réservations réelles ; le Lambda de l'Advisor ne peut en lire aucune, et aucune formulation dans la boîte de saisie n'y change quoi que ce soit.
That is not an argument against guardrails. They stop categories of request I would rather not serve, and they cost almost nothing to run. It is an argument about where to spend attention: a guardrail is a filter you tune, while a scoped role is a boundary the model cannot argue with. Ce n'est pas un argument contre les garde-fous. Ils bloquent des catégories de demandes que je préfère ne pas servir, et leur coût d'exécution est négligeable. C'est un argument sur l'endroit où placer son attention : un garde-fou est un filtre qu'on ajuste, tandis qu'un rôle restreint est une frontière avec laquelle le modèle ne peut pas négocier.
Keeping it freeLe garder gratuit
Two briefs per IP per day, counted with conditional writes so two simultaneous requests cannot both pass the same check. There is an allowlist I can manage from my own studio page for when I am testing and hit my own limit. Above all of it sits a monthly cap that nothing bypasses, including me — the allowlist raises the daily ceiling, never the monthly one. That asymmetry is deliberate: the daily limit protects the experience, the monthly limit protects the bill. Deux dossiers par adresse IP par jour, comptés par écritures conditionnelles pour que deux requêtes simultanées ne puissent pas franchir le même contrôle. Une liste d'autorisation, gérée depuis ma page studio, me sert quand je teste et que j'atteins ma propre limite. Au-dessus de tout cela se trouve un plafond mensuel que rien ne contourne, moi compris — la liste relève le plafond quotidien, jamais le mensuel. Cette asymétrie est voulue : la limite quotidienne protège l'expérience, la limite mensuelle protège la facture.
The Advisor is at /tools/ai-advisor.html. Describe something you have been meaning to build and see what comes back — and if it refuses something it clearly should not, that is worth telling me about, because every refusal in this article was found the same way. L'Advisor se trouve à /tools/ai-advisor.html. Décrivez quelque chose que vous songez à bâtir et voyez ce qui revient — et s'il refuse quelque chose qu'il ne devrait manifestement pas refuser, dites-le-moi : tous les refus décrits ici ont été découverts exactement de cette façon.