{"id":161319,"date":"2026-05-05T12:12:38","date_gmt":"2026-05-05T12:12:38","guid":{"rendered":"https:\/\/hnsecurity.it\/?p=161319"},"modified":"2026-05-05T12:12:38","modified_gmt":"2026-05-05T12:12:38","slug":"extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10","status":"publish","type":"post","link":"https:\/\/hnsecurity.it\/it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\/","title":{"rendered":"Extending Burp Suite for fun and profit \u2013 The Montoya way \u2013 Part 10"},"content":{"rendered":"<ol>\n<li><a href=\"https:\/\/hnsecurity.it\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-1\">Setting up the environment + Hello World<\/a><\/li>\n<li><a href=\"https:\/\/hnsecurity.it\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-2\">Inspecting and tampering HTTP requests and responses<\/a><\/li>\n<li><a href=\"https:\/\/hnsecurity.it\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-3\">Inspecting and tampering WebSocket messages<\/a><\/li>\n<li><a href=\"https:\/\/hnsecurity.it\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-4\">Creating new tabs for processing HTTP requests and responses<\/a><\/li>\n<li><a href=\"https:\/\/hnsecurity.it\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-5\/\">Adding new functionalities to the context menu (accessible by right-clicking)<\/a><\/li>\n<li><a href=\"https:\/\/hnsecurity.it\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-6\/\">Adding new checks to Burp Suite Active and Passive Scanner<\/a><\/li>\n<li><a href=\"https:\/\/hnsecurity.it\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-7\/\">Using the Collaborator in Burp Suite plugins<\/a><\/li>\n<li><a href=\"https:\/\/hnsecurity.it\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-8\/\">BChecks &#8211; A quick way to extend Burp Suite Active and Passive Scanner<\/a><\/li>\n<li><a href=\"https:\/\/hnsecurity.it\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-9\/\">Custom scan checks &#8211; An improved quick way to extend Burp Suite Active and Passive Scanner<\/a><\/li>\n<li><strong>Burp AI<\/strong><\/li>\n<li>&#8230; and much more!<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<p>Hi there!<\/p>\n<p>To kick off my collaboration with PortSwigger as a <a href=\"https:\/\/portswigger.net\/blog\/introducing-the-official-burp-ambassador-program\">Burp Suite Ambassador<\/a> and the <a href=\"https:\/\/x.com\/Burp_Suite\/status\/2049856390252921278\">Extensibility Month on PortSwigger Discord<\/a>, what better topic than AI, features recently introduced by PortSwigger to further expand the capabilities of the suite. On this topic, I\u2019m sure we\u2019ll see many new features in the future, but we already have APIs available that we can use to create powerful extensions!<\/p>\n<p>For a couple of years now at HN Security we\u2019ve been dedicating part of our R&amp;D time to the AI space, which has mainly led to the development of an <strong>internal AI red teaming methodology<\/strong>, but also to evaluating possible integrations of these technologies into our company\u2019s documentation tools and testing tools. At the moment, these integrations are still limited, both for compliance reasons and due to the agreements we have with our clients, but we are likely in a transition phase that could lead, in the near future, to a more pervasive use of these technologies, which could further improve the quality of our team\u2019s work.<\/p>\n<p>This article will focus on the use of the AI features currently offered by PortSwigger within extensions, without going for the moment into detail about their use within the Burp GUI, as that would be out of scope for this series of articles.<\/p>\n<p>To approach this topic, we are going to develop an extension that will simplify reporting of a issue, named <strong>AI Reporter<\/strong>. The idea is the following one: when we find an issue during our manual analyses, we want to use AI to analyze the request and response, extract the relevant information, and add a specific issue to Burp. For example, we\u2019re in Repeater, we discover a SQL injection, and from the context menu we select \u2018Report with AI\u2019, telling to the model that the current request proves a SQL injection. The tool will then take care of creating a specific issue for us with the details of the identified problem, including generic SQL Injection information and details on the particular issue extracted from request\/response.<\/p>\n<p>Usually, I always publish a PoC target to test the extension, but this time it is not necessary. You can try the extension with any previous target or with any other target in which you found an issue (remember that the extension will send these details to a third party; so if you want to try the extension during a PT you should be allowed to use third party LLM models). If you need a convenient target, the <a href=\"https:\/\/portswigger.net\/web-security\">PortSwigger Web Security Academy<\/a> has pretty much everything for any kind of application issue, such as <a href=\"https:\/\/portswigger.net\/web-security\/learning-paths\/sql-injection\">SQL Injection labs<\/a>.<\/p>\n<p><strong>Disclaimer: this extension by using Burp\u2019s AI features consumes AI Credits. At the moment, every user with a Burp Suite Professional license has 10,000 free credits, and once they are finished, additional credits need to be purchased. The extension\u2019s credit consumption is usually moderate, but it also depends on the size of the request\/response being reported.<\/strong><\/p>\n<p><strong>Disclaimer 2: as mentioned previously, the reported requests and responses, along with the data entered in the popup created by the extension, are sent to PortSwigger\u2019s AI infrastructure. You can find more details on Burp AI policy in the <a href=\"https:\/\/portswigger.net\/burp\/documentation\/desktop\/burp-ai\/trust\">Burp AI trust and compliance FAQ<\/a>.\u00a0<\/strong><\/p>\n<p>So, let&#8217;s start from the beginning. How can we use AI in our extension? We can get a reference to the\u00a0<em>Ai<\/em> object that we need from the usual <em>MontoyaApi\u00a0<\/em>object that we get when we initialize an extension:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-161325 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image.png\" alt=\"\" width=\"812\" height=\"447\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image.png 812w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-300x165.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-768x423.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-350x193.png 350w\" sizes=\"(max-width: 812px) 100vw, 812px\" \/><\/p>\n<p>As the documentation said, <strong>we need to do an extra step<\/strong>: in order to allow our extension to use AI features it need to declare its usage in the initialization:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-161326 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-2.png\" alt=\"\" width=\"910\" height=\"276\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-2.png 910w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-2-300x91.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-2-768x233.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-2-350x106.png 350w\" sizes=\"(max-width: 910px) 100vw, 910px\" \/><\/p>\n<p>So, we can build the skeleton of a new extension, as explained in <a href=\"https:\/\/hnsecurity.it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-1\/\">Part 1<\/a>, adding what it necessary to get access to the AI features:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">package org.fd;\r\n\r\nimport burp.api.montoya.BurpExtension;\r\nimport burp.api.montoya.EnhancedCapability;\r\nimport burp.api.montoya.MontoyaApi;\r\nimport burp.api.montoya.ai.Ai;\r\nimport burp.api.montoya.logging.Logging;\r\n\r\nimport java.util.Set;\r\n\r\nimport static burp.api.montoya.EnhancedCapability.AI_FEATURES;\r\n\r\npublic class AiReporter implements BurpExtension {\r\n\r\n    MontoyaApi api;\r\n    Ai ai;\r\n    Logging logging;\r\n    AiEngine aiEngine;\r\n    boolean debug;\r\n\r\n    @Override\r\n    public void initialize(MontoyaApi api) {\r\n\r\n        \/\/ Save a reference to the MontoyaApi object\r\n        this.api = api;\r\n\r\n        \/\/ Save a reference to the AI object\r\n        this.ai = api.ai();\r\n\r\n        \/\/ api.logging() returns an object that we can use to print messages to stdout and stderr\r\n        this.logging = api.logging();\r\n\r\n        \/\/ Set the name of the extension\r\n        api.extension().setName(\"AI Reporter\");\r\n\r\n        \/\/ Print a message to the stdout\r\n        this.logging.logToOutput(\"*** AI Reporter loaded ***\");\r\n\r\n        \/\/ Check if AI is enabled\r\n        if(this.ai.isEnabled())\r\n            this.logging.logToOutput(\"* AI enabled!\");\r\n        else\r\n            this.logging.logToError(\"* AI NOT enabled!\");\r\n\r\n        \/\/ Other initialization things\r\n        [...]\r\n\r\n    }\r\n\r\n    @Override\r\n    public Set&lt;EnhancedCapability&gt; enhancedCapabilities()  {\r\n        return Set.of(AI_FEATURES);\r\n    }\r\n\r\n}<\/pre>\n<p>As you can see, we declared the use of AI features by overriding the <em>enhancedCapabilities\u00a0<\/em>function, returning a set containing the <em>AI_FEATURES\u00a0<\/em>enum value.<\/p>\n<p>Furthermore, at the end of the <em>initialize\u00a0<\/em>function we used the\u00a0<em>isEnabled<\/em> function to check if AI functionalities are currently enabled:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-161443 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/04\/Pasted-image-3.png\" alt=\"\" width=\"929\" height=\"331\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/04\/Pasted-image-3.png 929w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/04\/Pasted-image-3-300x107.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/04\/Pasted-image-3-768x274.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/04\/Pasted-image-3-350x125.png 350w\" sizes=\"(max-width: 929px) 100vw, 929px\" \/><\/p>\n<p>Let&#8217;s spend a couple of word on when this method returns\u00a0<em>true<\/em>, necessary for being able to use the <em>prompt<\/em> method of the same class to use the AI features with our prompts.<\/p>\n<p>First, as we just said, we have to override the <em>enhancedCapabilities <\/em>(\u2705 done).<\/p>\n<p>Second, AI features should be globally enabled in Burp Suite. You can check this point in the bottom right corner of Burp Suite:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-161329 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-5.png\" alt=\"\" width=\"696\" height=\"340\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-5.png 696w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-5-300x147.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-5-350x171.png 350w\" sizes=\"(max-width: 696px) 100vw, 696px\" \/><\/p>\n<p>If that corner shows the &#8220;Disabled&#8221; message, AI features can be enabled in the <em>Settings<\/em> of Burp Suite, section <em>Ai<\/em>:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-161328 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-4.png\" alt=\"\" width=\"1044\" height=\"469\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-4.png 1044w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-4-300x135.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-4-1024x460.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-4-768x345.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-4-350x157.png 350w\" sizes=\"(max-width: 1044px) 100vw, 1044px\" \/><\/p>\n<p>Third and last point, we have to enabled AI functions in the Extensions tab. Here, some additional columns have been added to handle AI extensions, including a flag to enable\/disable AI features and the current AI credits consumption for each extension:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-161330 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-6.png\" alt=\"\" width=\"1156\" height=\"675\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-6.png 1156w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-6-300x175.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-6-1024x598.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-6-768x448.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-6-350x204.png 350w\" sizes=\"(max-width: 1156px) 100vw, 1156px\" \/><\/p>\n<p>If all these three conditions are met, we will read &#8220;* AI enabled!&#8221; in the Output pane of our extension.<\/p>\n<p>Now, let&#8217;s have a look of the main class of the extension, named <em>AiEngine.\u00a0<\/em>This class will define the object that we will use to use the AI in our extension, containing a simple prompt (that can be engineered on our preferences and needs) and the code that will use it.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">package org.fd;\r\n\r\nimport burp.api.montoya.ai.Ai;\r\nimport burp.api.montoya.ai.chat.Message;\r\nimport burp.api.montoya.ai.chat.PromptException;\r\nimport burp.api.montoya.ai.chat.PromptResponse;\r\n\r\nimport static burp.api.montoya.ai.chat.Message.*;\r\n\r\npublic class AiEngine {\r\n\r\n    public static final String SYSTEM_MESSAGE = \"\"\"\r\n            You are an expert penetration tester and application security analyst. Your task is to analyze an HTTP request\/response pair in which a specific vulnerability has been identified.\r\n            \r\n            You will receive:\r\n            - The vulnerability name (issue type)\r\n            - The HTTP request\r\n            - The HTTP response\r\n            - Optionally, additional details provided by the analyst\r\n            \r\n            Your objectives:\r\n            1. **Analyze** the request and response to locate concrete evidence of the reported vulnerability.\r\n            2. **Generate a title** that is specific and descriptive for this particular instance of the vulnerability (do not just repeat the generic vulnerability name \u2014 include context such as the affected parameter, endpoint, or functionality).\r\n            3. **Generate a detailed description** of the finding that includes:\r\n               - What the vulnerability is and why it is a security concern\r\n               - Where exactly in the request\/response the vulnerability manifests (cite specific parameters, headers, response content, or behavior)\r\n               - The potential impact if exploited by an attacker\r\n            4. **Generate remediation advice** that is specific and actionable for this particular case, not just generic best practices.\r\n            \r\n            Rules:\r\n            - Be precise: reference actual values, parameters, endpoints, and response content from the provided data.\r\n            - If additional details are provided by the analyst, incorporate them into your analysis.\r\n            - If you cannot find clear evidence of the vulnerability in the request\/response, state this explicitly in the details field.\r\n            - Write in a professional tone suitable for a penetration testing report.\r\n            - Respond ONLY with a valid JSON object, no additional text before or after it.\r\n            \r\n            Output format (strict JSON):\r\n            {\r\n              \"title\": \"Specific descriptive title of the finding\",\r\n              \"details\": \"Detailed description including evidence, location, and impact\",\r\n              \"remediation\": \"Specific and actionable remediation steps\"\r\n            }\r\n            \"\"\";\r\n\r\n    private final Message systemMessage;\r\n    Ai ai;\r\n\r\n    public AiEngine(Ai ai) {\r\n        this.systemMessage = systemMessage(SYSTEM_MESSAGE);\r\n        this.ai = ai;\r\n    }\r\n\r\n    \/\/ Function that call LLM using history (may throw a PromptException exception)\r\n    public String execute(String userPrompt) throws PromptException {\r\n\r\n        if(this.ai.isEnabled()) {\r\n\r\n            \/\/ Create the message array that includes the system prompt and the user message\r\n            Message[] messages = new Message[]{systemMessage, userMessage(userPrompt)};\r\n\r\n            \/\/ We execute the LLM call\r\n            PromptResponse response = this.ai.prompt().execute(messages);\r\n\r\n            \/\/ We return the assistant response\r\n            return response.content();\r\n\r\n        } else {\r\n\r\n            return null;\r\n\r\n        }\r\n\r\n    }\r\n\r\n    public boolean isAiEnabled() {\r\n        return this.ai.isEnabled();\r\n    }\r\n\r\n}\r\n<\/pre>\n<p>This class is very simple. We have a system prompt that instruct the LLM on the particular task and on the structure we expect for the output, a constructor the store the <em>Ai <\/em>object of the Montoya API, and a function, <em>execute<\/em>, that contains the main logic.<\/p>\n<p>The\u00a0<em>execute\u00a0<\/em>function first checks if the AI features are enabled and then calls the\u00a0<em>execute<\/em> function of the <em>Prompt<\/em> object, obtained from the Montoya API\u00a0<em>Ai<\/em> object:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-161336 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-7.png\" alt=\"\" width=\"1273\" height=\"474\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-7.png 1273w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-7-300x112.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-7-1024x381.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-7-768x286.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-7-350x130.png 350w\" sizes=\"(max-width: 1273px) 100vw, 1273px\" \/><\/p>\n<p>The\u00a0<em>execute\u00a0<\/em>function takes as argument a <strong>series<\/strong> of messages (an array of <em>Message<\/em> object), and not a single message. Why? This is because the APIs are structured in a way that allows us to separate the system prompt from the user messages and the assistant\u2019s responses. In the end, everything will be sent to the LLM itself all together (because the LLMs work that way), but the AI services offered by <span class=\"hover:entity-accent entity-underline inline cursor-pointer align-baseline\"><span class=\"whitespace-normal\">PortSwigger<\/span><\/span> will likely provide a structured separation of these messages, allowing the LLM to better understand who the different messages are coming from. The different message types we can use are the following ones:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-161337 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-8.png\" alt=\"\" width=\"1276\" height=\"377\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-8.png 1276w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-8-300x89.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-8-1024x303.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-8-768x227.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-8-350x103.png 350w\" sizes=\"(max-width: 1276px) 100vw, 1276px\" \/><\/p>\n<p>In a simple flow, like in our extension, we send the LLM two messages, a system message (with the prompt) plus a user message (with the user\u2019s question), and we receive an assistant message (with the response) in return. However, we can use these APIs to create more complex extensions, such as a chat with history, in which at each interaction we send to the LLM multiple user and assistant messages, and all those interactions are used by the LLM to produce its responses. In our extension we don&#8217;t need to maintain history but it is an interesting use case and I will add a <strong>PoC example at the end of the article<\/strong> that shows how to use history in AI extensions.<\/p>\n<p>Now let\u2019s go back to our extension. We\u2019ve looked at the object that will handle the AI part. Now we need to build the structure around it. We want to right-click on a request and directly create the issue, using AI to analyze the request\/response and write the issue. Therefore, we need to use Burp Suite <em>ContextMenuItemsProvider<\/em> APIs. We will look quickly at this portion of the extension, as we dived deeply in these functionalities in <a href=\"https:\/\/hnsecurity.it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-5\/\">part 5<\/a> of this tutorial. We will put the context menu login in a dedicated class, named\u00a0<em>AiReportedContextProvider<\/em>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">package org.fd;\r\n\r\nimport [...]\r\n\r\npublic class AiReporterContextProvider implements ContextMenuItemsProvider {\r\n\r\n    MontoyaApi api;\r\n    Logging logging;\r\n    JsonUtils jsonUtils;\r\n    AiEngine aiEngine;\r\n    boolean debug;\r\n\r\n    public AiReporterContextProvider(MontoyaApi api, AiEngine aiEngine, boolean debug) {\r\n\r\n        \/\/ Save a reference to the MontoyaApi object\r\n        this.api = api;\r\n        \/\/ Save a reference to the logging object of the MontoyaApi\r\n        this.logging = api.logging();\r\n        \/\/ Save a reference to JSON utilities\r\n        this.jsonUtils = api.utilities().jsonUtils();\r\n        \/\/ Save a reference to the object defined to handle AI\r\n        this.aiEngine = aiEngine;\r\n        \/\/ Debug variable\r\n        this.debug = debug;\r\n\r\n    }\r\n\r\n    public void reportWithAi(String vulnerability, AuditIssueSeverity severity, AuditIssueConfidence confidence,\r\n                             String additionalDetails, HttpRequestResponse reqRes) {\r\n        [...]\r\n    }\r\n\r\n    @Override\r\n    public List&lt;Component&gt; provideMenuItems(ContextMenuEvent event) {\r\n\r\n        \/\/ Initialize an empty list that will contains our context menu entries\r\n        List&lt;Component&gt; menuItems = new ArrayList&lt;Component&gt;();\r\n\r\n        \/\/ Create the menu only if the menu has been created on a request\/response object\r\n        event.messageEditorRequestResponse().ifPresent(messageEditorReqRes -&gt; {\r\n\r\n            \/\/ Get the HTTP message\r\n            HttpRequestResponse reqRes = messageEditorReqRes.requestResponse();\r\n\r\n            \/\/ Add the \"Report with AI\" context menu item with its listener\r\n            JMenuItem reportWithAiItem = new JMenuItem(\"Report with AI\");\r\n            reportWithAiItem.addActionListener(al -&gt; {\r\n\r\n                \/\/ Show only if AI features are enabled\r\n                if(this.aiEngine.isAiEnabled()) {\r\n\r\n                    AiReporterDialog dialog = AiReporterDialog.show(null);\r\n\r\n                    \/\/ If the dialog is confirmed call the reportWithAi function that will call the LLM and report the issue\r\n                    if (dialog.isConfirmed()) {\r\n                        String vulnerability = dialog.getVulnerability();\r\n                        AuditIssueSeverity severity = dialog.getSeverity();\r\n                        AuditIssueConfidence confidence = dialog.getConfidence();\r\n                        String additionalDetails = dialog.getAdditionalDetails();\r\n\r\n                        \/\/ A new thread is necessary because we cannot call the LLM function inside the GUI thread\r\n                        \/\/ to avoid blocking Burp\r\n                        new Thread(() -&gt; {\r\n                            reportWithAi(vulnerability, severity, confidence, additionalDetails, reqRes);\r\n                        }).start();\r\n\r\n                    }\r\n\r\n                } else {\r\n\r\n                    JOptionPane.showMessageDialog(null, \"Please enable Burp AI features to \" +\r\n                                    \"use this extension (additional costs may be charged)\",\r\n                            \"Burp AI disabled\", JOptionPane.INFORMATION_MESSAGE);\r\n                }\r\n\r\n            });\r\n\r\n            menuItems.add(reportWithAiItem);\r\n\r\n        });\r\n\r\n        return menuItems;\r\n\r\n    }\r\n\r\n}<\/pre>\n<p>This code simply saves references to objects we will use in the constructor and then override the <em>provideMenuItems\u00a0<\/em>function of the implemented <em>ContextMenuItemsProvider<\/em> interface. Here we add the &#8220;Report with AI&#8221; context menu entry only if the user clicked on a request\/response and if the AI features are enabled. Once clicked, a new popup is shown to the user, designed in class <em>AiReporterDialog\u00a0<\/em>with Java Swing, asking for a couple of information that will be used during generation. In this chapter, we won\u2019t go into detail about how to create graphical user interfaces in Java (not a fun task at all, trust me!). We might cover an introduction in future episodes. If you need to create a Java GUI before then, Claude\/Gemini\/ChatGPT &amp; co. will definitely be able to help you! The popup, once opened, will look this way:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-161344 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-16-37-50.png\" alt=\"\" width=\"801\" height=\"337\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-16-37-50.png 801w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-16-37-50-300x126.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-16-37-50-768x323.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-16-37-50-350x147.png 350w\" sizes=\"(max-width: 801px) 100vw, 801px\" \/><\/p>\n<p>&#8220;Severity&#8221; and &#8220;confidence&#8221; will be used only to create the issue, while &#8220;vulnerability&#8221; and &#8220;additional details&#8221; will be supplied to the LLM, together with the request\/response for the generation. The idea is the following: in most cases, it\u2019s enough to enter the title of the issue (e.g., SQL Injection), and the LLM will take care of identifying the issue in the request\/response, extracting the important information, and generating the issue report.<\/p>\n<p>\u201cAdditional details\u201d is occasionally used for issues where there is no direct evidence of the problem in the single request\/response. For example, in the case of an authorization bypass, the user can specify that the current user he is using does not have access to the resource he was able to access in the request\/response selected for the report (information that is not contained in the response itself). We will see a couple of examples of the extension in use in a moment.<\/p>\n<p>Now, let&#8217;s have a look to the function <em>reportWithAi, <\/em>that will call the Ai engine and report the issue:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">\/\/ Burp AI often returns markdown code block tags in the response also if denied in the prompt.\r\n\/\/ This method strip markdown code block tags in the response using Lambda expressions.\r\nprivate String cleanJsonResponse(String response) {\r\n    return response.lines()\r\n            .filter(line -&gt; !line.trim().startsWith(\"```\"))\r\n            .collect(Collectors.joining(\"\\n\"))\r\n            .trim();\r\n}\r\n\r\n\/\/ Call the AI Engine and report the issue\r\npublic void reportWithAi(String vulnerability, AuditIssueSeverity severity, AuditIssueConfidence confidence, String additionalDetails, HttpRequestResponse reqRes) {\r\n\r\n    \/\/ If AI features are enabled\r\n    if(this.aiEngine.isAiEnabled()) {\r\n\r\n        \/\/ User message format\r\n        String userMessage = \"\"\"\r\n                Vulnerability name: %s\r\n                \r\n                HTTP Request:\r\n                %s\r\n                \r\n                HTTP Response:\r\n                %s\r\n                \r\n                Additional details: %s\r\n                \"\"\".formatted(vulnerability, reqRes.request().toString(),\r\n                    reqRes.response().toString(), additionalDetails);\r\n\r\n        String title;\r\n        String details;\r\n        String remediation;\r\n\r\n        try  {\r\n            \/\/ Call the LLM with the user message\r\n            String promptResponse = aiEngine.execute(userMessage);\r\n\r\n            if(promptResponse != null) {\r\n\r\n                \/\/ Remove markdown code block tags in LLM response\r\n                String cleanedResponse = cleanJsonResponse(promptResponse);\r\n\r\n                \/\/ LLM response is formatted in JSON, as requested in our prompt\r\n                if (this.jsonUtils.isValidJson(cleanedResponse)) {\r\n\r\n                    \/\/ Extract from JSON the details of the issue generated by the LLM\r\n                    title = this.jsonUtils.readString(cleanedResponse, \"title\");\r\n                    details = this.jsonUtils.readString(cleanedResponse, \"details\");\r\n                    remediation = this.jsonUtils.readString(cleanedResponse, \"remediation\");\r\n\r\n                } else {\r\n                    this.logging.logToError(\"* AI Reporter: invalid JSON in AI response\");\r\n                    return;\r\n                }\r\n\r\n            } else {\r\n                this.logging.logToError(\"* AI Reporter: AI not enabled\");\r\n                return;\r\n            }\r\n\r\n        } catch (PromptException e)  {\r\n            this.logging.logToError(\"Issue executing prompt\", e);\r\n            return;\r\n        }\r\n\r\n        \/\/ Report issue in Burp Suite with AI details\r\n        AuditIssue auditIssue = AuditIssue.auditIssue(title,\r\n                details,\r\n                remediation,\r\n                reqRes.request().url(),\r\n                severity,\r\n                confidence,\r\n                null, \/\/ background\r\n                null, \/\/ remediationBackground\r\n                severity,\r\n                reqRes);\r\n\r\n        this.api.siteMap().add(auditIssue);\r\n\r\n    } else {\r\n        this.logging.logToError(\"* AI Reporter: AI features disabled.\");\r\n    }\r\n\r\n}<\/pre>\n<p>The <em>reportWithAi<\/em> method takes as arguments all the information entered by the user in the popup plus the request\/response pair. This information is included in the user message, which will then be sent to the LLM together with the system prompt.<\/p>\n<p>As we saw earlier, the prompt asks the LLM to generate the response in JSON format, so we will use the JSON utilities provided by the Montoya API (<em>api.utilities().jsonUtils()<\/em>) to extract the title, details, and remediation from the response received from the LLM. However, you can see from the code that before extracting the JSON values the <em>clearJsonResponse<\/em> method is executed on the response obtained from the LLM. The reason is that the LLM often (though not always) returned the JSON wrapped inside Markdown code blocks (&#8220;`), even when explicitly forbidden in the prompt. With LLMs, situations like this can happen and can often be resolved by tuning the prompt. In this case, even after some prompt tuning, I would occasionally still get Markdown tags, so I preferred to strip them out in code.<\/p>\n<p>Finally, we use the information extracted from the LLM response to create an issue in Burp Suite (for more information on this topic, refer to <a href=\"https:\/\/hnsecurity.it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-6\/\">Part 6<\/a>).<\/p>\n<p>Our extension is now complete. We have only to register the context menu item provider in the\u00a0<em>initialize<\/em> function:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">public class AiReporter implements BurpExtension {\r\n\r\n    [...]\r\n\r\n    @Override\r\n    public void initialize(MontoyaApi api) {\r\n\r\n        [...]\r\n\r\n        \/\/ Register our Context Menu Item Provider\r\n        AiReporterContextProvider customContextMenuItemProvider = new AiReporterContextProvider(api,this.aiEngine, this.debug);\r\n        api.userInterface().registerContextMenuItemsProvider(customContextMenuItemProvider);\r\n\r\n    }\r\n\r\n}\r\n\r\n<\/pre>\n<p>Now we can build the extension and try it on a couple of vulnerable requests (refer to <a href=\"https:\/\/hnsecurity.it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-1\/\">Part 1<\/a> to details on how to compile and package the extension).<\/p>\n<p>Let&#8217;s start with a simple SQL Injection.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-161357 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-10.png\" alt=\"\" width=\"1373\" height=\"571\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-10.png 1373w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-10-300x125.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-10-1024x426.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-10-768x319.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-10-350x146.png 350w\" sizes=\"(max-width: 1373px) 100vw, 1373px\" \/><\/p>\n<p>Let&#8217;s try our extension supplying only the title:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-161353 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-17-30-46.png\" alt=\"\" width=\"1379\" height=\"616\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-17-30-46.png 1379w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-17-30-46-300x134.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-17-30-46-1024x457.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-17-30-46-768x343.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-17-30-46-350x156.png 350w\" sizes=\"(max-width: 1379px) 100vw, 1379px\" \/><\/p>\n<p>And here the result:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-161358 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-11.png\" alt=\"\" width=\"1147\" height=\"708\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-11.png 1147w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-11-300x185.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-11-1024x632.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-11-768x474.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-11-350x216.png 350w\" sizes=\"(max-width: 1147px) 100vw, 1147px\" \/><\/p>\n<p>Now, let&#8217;s try with a simple reflected XSS:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-161356 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-12-1.png\" alt=\"\" width=\"1376\" height=\"575\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-12-1.png 1376w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-12-1-300x125.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-12-1-1024x428.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-12-1-768x321.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-12-1-350x146.png 350w\" sizes=\"(max-width: 1376px) 100vw, 1376px\" \/><\/p>\n<p>As before, we simply supply a generic title to the issue:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-161354 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-17-35-30.png\" alt=\"\" width=\"1379\" height=\"616\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-17-35-30.png 1379w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-17-35-30-300x134.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-17-35-30-1024x457.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-17-35-30-768x343.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-17-35-30-350x156.png 350w\" sizes=\"(max-width: 1379px) 100vw, 1379px\" \/><\/p>\n<p>And here the result:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-161350 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-13.png\" alt=\"\" width=\"1142\" height=\"740\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-13.png 1142w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-13-300x194.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-13-1024x664.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-13-768x498.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-13-350x227.png 350w\" sizes=\"(max-width: 1142px) 100vw, 1142px\" \/><\/p>\n<p>Finally, let&#8217;s try our extension on an authorization bypass (direct object reference). In this example we can see details of transfer with ID 3 with a user that should not have access to it:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-161351 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-14.png\" alt=\"\" width=\"1376\" height=\"563\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-14.png 1376w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-14-300x123.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-14-1024x419.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-14-768x314.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-14-350x143.png 350w\" sizes=\"(max-width: 1376px) 100vw, 1376px\" \/><\/p>\n<p>We supply this additional information to the LLM because it cannot infer it simply by the request\/response.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-161355 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-17-41-14.png\" alt=\"\" width=\"1379\" height=\"616\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-17-41-14.png 1379w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-17-41-14-300x134.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-17-41-14-1024x457.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-17-41-14-768x343.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Screenshot-From-2026-02-23-17-41-14-350x156.png 350w\" sizes=\"(max-width: 1379px) 100vw, 1379px\" \/><\/p>\n<p>And here the result:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-161352 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-15.png\" alt=\"\" width=\"1140\" height=\"733\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-15.png 1140w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-15-300x193.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-15-1024x658.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-15-768x494.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-15-350x225.png 350w\" sizes=\"(max-width: 1140px) 100vw, 1140px\" \/><\/p>\n<p>As we can see, with a simple prompt we got some pretty good results. Obviously, we can improve the results in order to fit better the results with our needs. Some examples of improvements we can implement on our prompt are:<\/p>\n<ul>\n<li>Tuning the instructions<\/li>\n<li>Examples of desired results (one shot \/ few shots)<\/li>\n<li>Maybe use dedicated prompts for the issue sections (details, title, remediation, etc.)<\/li>\n<li>Enforce positive and negative bonds<\/li>\n<li>Use delimiters to divide sections of the prompt<\/li>\n<li>Repeat most important instructions more times (yes, sometimes it works&#8230;)<\/li>\n<li>etc&#8230;<\/li>\n<\/ul>\n<p>Before ending this article, let&#8217;s have a look to a simple PoC of a chat with history implemented in Burp Suite (it&#8217;s only a PoC of the chat engine, without the GUI code \ud83d\ude09 ), in a dedicated class named <em>AiEngineWithHistory <\/em>not used in our extension. In order to achieve this result, we will use the array of messages to store all the previous questions and answers, beside the current one and the system prompt.<\/p>\n<p>The system message will be added first and will contain the system prompt. Then we will have sequences of user messages with questions and assistant messages with responses. By supplying the whole history to the LLM, it will consider all the message to produce the response because all the messages will be in its context. In scenarios like an interactive chat, this is very valuable. Let&#8217;s have a look at a practical example (NOT related to the AI Reported extension but useful to understand the AI APIs of Burp Suite):<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">package org.fd;\r\n\r\nimport burp.api.montoya.ai.Ai;\r\nimport burp.api.montoya.ai.chat.Message;\r\nimport burp.api.montoya.ai.chat.PromptException;\r\nimport burp.api.montoya.ai.chat.PromptResponse;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.stream.Collectors;\r\n\r\nimport static burp.api.montoya.ai.chat.Message.systemMessage;\r\nimport static burp.api.montoya.ai.chat.Message.assistantMessage;\r\nimport static burp.api.montoya.ai.chat.Message.userMessage;\r\n\r\npublic class AiEngineWithHistory {\r\n\r\n    public static final String SYSTEM_MESSAGE = \"You are an expert penetration tester and application security analyst. Your task is to help user with his questions.\";\r\n\r\n    private final Message systemMessage;\r\n    Map&lt;String, List&lt;Message&gt;&gt; history;\r\n    Ai ai;\r\n\r\n    public AiEngineWithHistory(Ai ai) {\r\n        \/\/ Create a SYSTEM message object\r\n        this.systemMessage = systemMessage(SYSTEM_MESSAGE);\r\n        \/\/ Instantiate a Map to hold the history\r\n        this.history = new HashMap&lt;String,List&lt;Message&gt;&gt;();\r\n        \/\/ Save a reference to the AI object\r\n        this.ai = ai;\r\n    }\r\n\r\n    \/\/ Function that call LLM using history\r\n    public String execute(String chatId, String userPrompt) throws PromptException {\r\n\r\n        if(this.ai.isEnabled()) {\r\n\r\n            \/\/ If our history does not contain an entry for the supplied chat ID (case: new chat)\r\n            \/\/ we create a new entry in our history with the SYSTEM message as first message\r\n            if (!(this.history.containsKey(chatId))) {\r\n                List&lt;Message&gt; newList = new ArrayList&lt;Message&gt;();\r\n                newList.add(this.systemMessage);\r\n                this.history.put(chatId, newList);\r\n            }\r\n\r\n            \/\/ We get a reference to the history of the current chat ID\r\n            List&lt;Message&gt; currentList = this.history.get(chatId);\r\n\r\n            \/\/We add the new user message to the list\r\n            currentList.add(userMessage(userPrompt));\r\n\r\n            \/\/ We send the full message list to the AI, in order to receive a response\r\n            \/\/ that consider the whole message history\r\n            PromptResponse response = this.ai.prompt().execute(currentList.toArray(Message[]::new));\r\n\r\n            \/\/ We save the LLM response as an assistant message in the history\r\n            currentList.add(assistantMessage(response.content()));\r\n\r\n            \/\/ TODO: Trim?\r\n\r\n            \/\/ We return the assistant response\r\n            return response.content();\r\n\r\n        } else {\r\n\r\n            return null;\r\n\r\n        }\r\n\r\n    }\r\n\r\n    \/\/ Function that convert the history of a chat to a string using Lambda expressions\r\n    public String toString(String chatId) {\r\n\r\n        if(this.history.containsKey(chatId)) {\r\n\r\n            return this.history.get(chatId).stream()\r\n                    .map(Message::toString)\r\n                    .collect(Collectors.joining(\"\\n\"));\r\n\r\n        } else {\r\n            return null;\r\n        }\r\n\r\n    }\r\n\r\n    public boolean isAiEnabled() {\r\n        return this.ai.isEnabled();\r\n    }\r\n\r\n}\r\n<\/pre>\n<p>The code is quite well commented, but substantially we use a <em>Map\u00a0<\/em>object to store our history. The key of the map is a chat identifier (because this way we can handle more chats) and the value is a list of messages. When the user call the <em>execute<\/em> method supplying a message and a chat identifier, we check in our Map if we already have a reference to that particular chat. If not, we create a new entry in the map with a list containing the system prompt. Then, we add the user message to the chat, we call the LLM and we store the assistant response in the same list, before returning the assistant message to the user. With this approach, we keep a full history of all the messages in the chat sessions and when a new user message is executed with an existing chat identifier, all the previous messages are sent to the LLM with the new one, giving to the LLM more context. Let&#8217;s try our class to try if it is working correctly (the code has been added to the <em>initialize<\/em> function just for this try):<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">AiEngineWithHistory aiHistory = new AiEngineWithHistory(this.ai);\r\n\r\nnew Thread(() -&gt; {\r\n\r\n    String chatId = \"firstChatId\";\r\n\r\n    String firstQuestion = \"Hi, please explain me what is a XSS in one sentence.\";\r\n    String firstAnswer = aiHistory.execute(chatId, firstQuestion);\r\n    this.logging.logToOutput(\"First question: \" + firstQuestion);\r\n    this.logging.logToOutput(\"First answer: \" + firstAnswer);\r\n    this.logging.logToOutput(\"\");\r\n\r\n    String secondQuestion = \"What is the last thing I asked you?\";\r\n    String secondAnswer = aiHistory.execute(chatId, secondQuestion);\r\n    this.logging.logToOutput(\"Second question: \" + secondQuestion);\r\n    this.logging.logToOutput(\"Second answer: \" + secondAnswer);\r\n    this.logging.logToOutput(\"\");\r\n\r\n    this.logging.logToOutput(\"Full history of chat \" + chatId + \":\");\r\n    this.logging.logToOutput(aiHistory.toString(chatId));\r\n\r\n}).start();<\/pre>\n<p>By running this code we can see that the second question ask details on the first one, receiving the correct answer, and the history includes all the messages of the chat:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-161339 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-9.png\" alt=\"\" width=\"1798\" height=\"652\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-9.png 1798w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-9-300x109.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-9-1024x371.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-9-768x278.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-9-1536x557.png 1536w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/02\/Pasted-image-9-350x127.png 350w\" sizes=\"(max-width: 1798px) 100vw, 1798px\" \/><\/p>\n<p>I will leave class <em>AiEngineWithHistory\u00a0<\/em>in the source code of the extension, along with the class to try it commented in the <em>initialize<\/em> function.<\/p>\n<p>Keep in mind that if you build a chat, there are additional complexities to address. As the number and size of messages in the history increase, not only do token usage and costs go up, but you may also run out of available context space or cause a \u201cdilution\u201d of the system prompt instructions (or even a complete loss of its instructions). These are more advanced concepts in developing LLM-based tools that we can&#8217;t approaching now, but they definitely need to be taken into consideration.<\/p>\n<p>As always, the complete code can be downloaded from\u00a0<a href=\"https:\/\/github.com\/federicodotta\/Burp-Suite-Extender-Montoya-Course\">my GitHub repository.<\/a><\/p>\n<p>If you liked the extension we developed, I\u2019m about to submit \/ I\u2019m submitting \/ I\u2019ll be submitting (depending on when I publish the article and manage to finish the extension \ud83d\ude04) a more complete version of it to the BApp Store, with a few additional features.<\/p>\n<p>Official documentation and examples can be found at the following links:<\/p>\n<ul>\n<li><a href=\"https:\/\/portswigger.github.io\/burp-extensions-montoya-api\/javadoc\/burp\/api\/montoya\/MontoyaApi.html\">Montoya API docs<\/a><\/li>\n<li><a href=\"https:\/\/portswigger.net\/burp\/documentation\/desktop\/extend-burp\/extensions\/creating\/creating-ai-extensions\/best-practices\">PortSwigger best practices for writing AI extensions<\/a><\/li>\n<\/ul>\n<p>Last but not least, as I mentioned at the beginning of this article, May will be dedicated to extensibility on the PortSwigger Discord, with events and resources focused on extensibility in Burp Suite. I will also be hosting an event on this topic titled &#8220;Restoring Testability: Handling Complex Scenarios in Burp Suite with a Custom Extension&#8221; on May 14. If you are interested in the topic you can join the <a href=\"https:\/\/discord.gg\/portswigger\">PortSwigger Discord server here<\/a> and you can find <a href=\"https:\/\/discord.gg\/portswigger?event=1499761261750128670\">my event here<\/a>.<\/p>\n<p>I hope you enjoyed this chapter. See you soon!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Setting up the environment + Hello World Inspecting and tampering HTTP requests and responses Inspecting and tampering WebSocket messages Creating [&hellip;]<\/p>\n","protected":false},"author":4,"featured_media":159898,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[88,91],"tags":[104,188,220,519,570],"class_list":["post-161319","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tools","category-articles","tag-burp-suite","tag-montoya-api","tag-ai","tag-llm","tag-portswigger"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>HN Security - Extending Burp Suite for fun and profit \u2013 The Montoya way \u2013 Part 10 - Articles<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/hnsecurity.it\/it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\/\" \/>\n<meta property=\"og:locale\" content=\"it_IT\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"HN Security - Extending Burp Suite for fun and profit \u2013 The Montoya way \u2013 Part 10 - Articles\" \/>\n<meta property=\"og:description\" content=\"Setting up the environment + Hello World Inspecting and tampering HTTP requests and responses Inspecting and tampering WebSocket messages Creating [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/hnsecurity.it\/it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\/\" \/>\n<meta property=\"og:site_name\" content=\"HN Security\" \/>\n<meta property=\"article:published_time\" content=\"2026-05-05T12:12:38+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/09\/BURP.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1600\" \/>\n\t<meta property=\"og:image:height\" content=\"836\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Federico Dotta\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@hnsec\" \/>\n<meta name=\"twitter:site\" content=\"@hnsec\" \/>\n<meta name=\"twitter:label1\" content=\"Scritto da\" \/>\n\t<meta name=\"twitter:data1\" content=\"Federico Dotta\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tempo di lettura stimato\" \/>\n\t<meta name=\"twitter:data2\" content=\"17 minuti\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/blog\\\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/blog\\\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\\\/\"},\"author\":{\"name\":\"Federico Dotta\",\"@id\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/#\\\/schema\\\/person\\\/e0e6046bd2bc829f7d945ad361bce702\"},\"headline\":\"Extending Burp Suite for fun and profit \u2013 The Montoya way \u2013 Part 10\",\"datePublished\":\"2026-05-05T12:12:38+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/blog\\\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\\\/\"},\"wordCount\":2824,\"publisher\":{\"@id\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/blog\\\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/hnsecurity.it\\\/wp-content\\\/uploads\\\/2025\\\/09\\\/BURP.jpg\",\"keywords\":[\"Burp Suite\",\"Montoya API\",\"ai\",\"LLM\",\"PortSwigger\"],\"articleSection\":[\"Tools\",\"Articles\"],\"inLanguage\":\"it-IT\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/blog\\\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\\\/\",\"url\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/blog\\\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\\\/\",\"name\":\"HN Security - Extending Burp Suite for fun and profit \u2013 The Montoya way \u2013 Part 10 - Articles\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/blog\\\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/blog\\\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/hnsecurity.it\\\/wp-content\\\/uploads\\\/2025\\\/09\\\/BURP.jpg\",\"datePublished\":\"2026-05-05T12:12:38+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/blog\\\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\\\/#breadcrumb\"},\"inLanguage\":\"it-IT\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/hnsecurity.it\\\/it\\\/blog\\\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/blog\\\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\\\/#primaryimage\",\"url\":\"https:\\\/\\\/hnsecurity.it\\\/wp-content\\\/uploads\\\/2025\\\/09\\\/BURP.jpg\",\"contentUrl\":\"https:\\\/\\\/hnsecurity.it\\\/wp-content\\\/uploads\\\/2025\\\/09\\\/BURP.jpg\",\"width\":1600,\"height\":836},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/blog\\\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Extending Burp Suite for fun and profit \u2013 The Montoya way \u2013 Part 10\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/#website\",\"url\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/\",\"name\":\"HN Security\",\"description\":\"Offensive Security Specialists\",\"publisher\":{\"@id\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"it-IT\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/#organization\",\"name\":\"HN Security\",\"url\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/hnsecurity.it\\\/wp-content\\\/uploads\\\/2026\\\/01\\\/hn-libellula.jpg\",\"contentUrl\":\"https:\\\/\\\/hnsecurity.it\\\/wp-content\\\/uploads\\\/2026\\\/01\\\/hn-libellula.jpg\",\"width\":696,\"height\":696,\"caption\":\"HN Security\"},\"image\":{\"@id\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/x.com\\\/hnsec\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/hnsecurity\\\/\",\"https:\\\/\\\/github.com\\\/hnsecurity\",\"https:\\\/\\\/infosec.exchange\\\/@hnsec\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/#\\\/schema\\\/person\\\/e0e6046bd2bc829f7d945ad361bce702\",\"name\":\"Federico Dotta\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/02d5d800b81f2a125ac23ee31a108ee2404d123bd3b722f2e263f0130cc1df42?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/02d5d800b81f2a125ac23ee31a108ee2404d123bd3b722f2e263f0130cc1df42?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/02d5d800b81f2a125ac23ee31a108ee2404d123bd3b722f2e263f0130cc1df42?s=96&d=mm&r=g\",\"caption\":\"Federico Dotta\"},\"url\":\"https:\\\/\\\/hnsecurity.it\\\/it\\\/blog\\\/author\\\/federico-dotta\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"HN Security - Extending Burp Suite for fun and profit \u2013 The Montoya way \u2013 Part 10 - Articles","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/hnsecurity.it\/it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\/","og_locale":"it_IT","og_type":"article","og_title":"HN Security - Extending Burp Suite for fun and profit \u2013 The Montoya way \u2013 Part 10 - Articles","og_description":"Setting up the environment + Hello World Inspecting and tampering HTTP requests and responses Inspecting and tampering WebSocket messages Creating [&hellip;]","og_url":"https:\/\/hnsecurity.it\/it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\/","og_site_name":"HN Security","article_published_time":"2026-05-05T12:12:38+00:00","og_image":[{"width":1600,"height":836,"url":"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/09\/BURP.jpg","type":"image\/jpeg"}],"author":"Federico Dotta","twitter_card":"summary_large_image","twitter_creator":"@hnsec","twitter_site":"@hnsec","twitter_misc":{"Scritto da":"Federico Dotta","Tempo di lettura stimato":"17 minuti"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/hnsecurity.it\/it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\/#article","isPartOf":{"@id":"https:\/\/hnsecurity.it\/it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\/"},"author":{"name":"Federico Dotta","@id":"https:\/\/hnsecurity.it\/it\/#\/schema\/person\/e0e6046bd2bc829f7d945ad361bce702"},"headline":"Extending Burp Suite for fun and profit \u2013 The Montoya way \u2013 Part 10","datePublished":"2026-05-05T12:12:38+00:00","mainEntityOfPage":{"@id":"https:\/\/hnsecurity.it\/it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\/"},"wordCount":2824,"publisher":{"@id":"https:\/\/hnsecurity.it\/it\/#organization"},"image":{"@id":"https:\/\/hnsecurity.it\/it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\/#primaryimage"},"thumbnailUrl":"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/09\/BURP.jpg","keywords":["Burp Suite","Montoya API","ai","LLM","PortSwigger"],"articleSection":["Tools","Articles"],"inLanguage":"it-IT"},{"@type":"WebPage","@id":"https:\/\/hnsecurity.it\/it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\/","url":"https:\/\/hnsecurity.it\/it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\/","name":"HN Security - Extending Burp Suite for fun and profit \u2013 The Montoya way \u2013 Part 10 - Articles","isPartOf":{"@id":"https:\/\/hnsecurity.it\/it\/#website"},"primaryImageOfPage":{"@id":"https:\/\/hnsecurity.it\/it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\/#primaryimage"},"image":{"@id":"https:\/\/hnsecurity.it\/it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\/#primaryimage"},"thumbnailUrl":"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/09\/BURP.jpg","datePublished":"2026-05-05T12:12:38+00:00","breadcrumb":{"@id":"https:\/\/hnsecurity.it\/it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\/#breadcrumb"},"inLanguage":"it-IT","potentialAction":[{"@type":"ReadAction","target":["https:\/\/hnsecurity.it\/it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\/"]}]},{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/hnsecurity.it\/it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\/#primaryimage","url":"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/09\/BURP.jpg","contentUrl":"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/09\/BURP.jpg","width":1600,"height":836},{"@type":"BreadcrumbList","@id":"https:\/\/hnsecurity.it\/it\/blog\/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-10\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/hnsecurity.it\/it\/"},{"@type":"ListItem","position":2,"name":"Extending Burp Suite for fun and profit \u2013 The Montoya way \u2013 Part 10"}]},{"@type":"WebSite","@id":"https:\/\/hnsecurity.it\/it\/#website","url":"https:\/\/hnsecurity.it\/it\/","name":"HN Security","description":"Offensive Security Specialists","publisher":{"@id":"https:\/\/hnsecurity.it\/it\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/hnsecurity.it\/it\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"it-IT"},{"@type":"Organization","@id":"https:\/\/hnsecurity.it\/it\/#organization","name":"HN Security","url":"https:\/\/hnsecurity.it\/it\/","logo":{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/hnsecurity.it\/it\/#\/schema\/logo\/image\/","url":"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/01\/hn-libellula.jpg","contentUrl":"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/01\/hn-libellula.jpg","width":696,"height":696,"caption":"HN Security"},"image":{"@id":"https:\/\/hnsecurity.it\/it\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/hnsec","https:\/\/www.linkedin.com\/company\/hnsecurity\/","https:\/\/github.com\/hnsecurity","https:\/\/infosec.exchange\/@hnsec"]},{"@type":"Person","@id":"https:\/\/hnsecurity.it\/it\/#\/schema\/person\/e0e6046bd2bc829f7d945ad361bce702","name":"Federico Dotta","image":{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/secure.gravatar.com\/avatar\/02d5d800b81f2a125ac23ee31a108ee2404d123bd3b722f2e263f0130cc1df42?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/02d5d800b81f2a125ac23ee31a108ee2404d123bd3b722f2e263f0130cc1df42?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/02d5d800b81f2a125ac23ee31a108ee2404d123bd3b722f2e263f0130cc1df42?s=96&d=mm&r=g","caption":"Federico Dotta"},"url":"https:\/\/hnsecurity.it\/it\/blog\/author\/federico-dotta\/"}]}},"jetpack_featured_media_url":"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/09\/BURP.jpg","_links":{"self":[{"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/posts\/161319","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/comments?post=161319"}],"version-history":[{"count":32,"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/posts\/161319\/revisions"}],"predecessor-version":[{"id":161494,"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/posts\/161319\/revisions\/161494"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/media\/159898"}],"wp:attachment":[{"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/media?parent=161319"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/categories?post=161319"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/tags?post=161319"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}