<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Charles Givre</title>
    <description>The latest articles on DEV Community by Charles Givre (@cgivre).</description>
    <link>https://dev.to/cgivre</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3883009%2Fba7ddf6d-09fc-423d-a56d-0615322da2e3.png</url>
      <title>DEV Community: Charles Givre</title>
      <link>https://dev.to/cgivre</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cgivre"/>
    <language>en</language>
    <item>
      <title>How to Brief a Board on AI Security: A CISO's Structure</title>
      <dc:creator>Charles Givre</dc:creator>
      <pubDate>Wed, 29 Jul 2026 14:06:43 +0000</pubDate>
      <link>https://dev.to/cgivre/how-to-brief-a-board-on-ai-security-a-cisos-structure-2646</link>
      <guid>https://dev.to/cgivre/how-to-brief-a-board-on-ai-security-a-cisos-structure-2646</guid>
      <description>&lt;p&gt;The EU AI Act's high-risk obligations arrive in August 2026, and a lot of security leaders are about to give their first serious AI briefing to a board that has started asking pointed questions. Most of those briefings will go badly, for a predictable reason: they will describe AI risk in general terms when the board wants to know about this company.&lt;/p&gt;

&lt;p&gt;A board does not need an education in transformer architectures. It needs to know whether the organization is exposed, who owns the problem, and what decision is being asked of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the board is actually deciding
&lt;/h2&gt;

&lt;p&gt;Boards do not manage risk. They allocate authority and money, and they establish whether management has the situation in hand. Every AI security briefing should therefore end in a specific ask: fund an inventory, authorize an approval gate with teeth, accept a documented risk, or approve headcount.&lt;/p&gt;

&lt;p&gt;If you reach the end of your slot without asking for something, you have delivered a status report. Boards tolerate those and forget them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bring four numbers you can defend
&lt;/h2&gt;

&lt;p&gt;The difference between a credible briefing and a nervous one is whether the speaker can say where each number came from. Four are worth the slot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How many AI systems are deployed, and how many have a named owner.&lt;/strong&gt; The owner count matters more than the total. Pull the list from procurement records, your CMDB, and the OAuth application grants in your identity provider (Entra ID or Okta will show you which third-party AI tools employees have already connected to corporate accounts, which is usually the number that surprises people).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What data classes are reaching external model providers.&lt;/strong&gt; Source this from DLP and egress tooling (Microsoft Purview, Netskope, Zscaler) rather than from policy. Policy tells the board what is permitted. The board is asking what is happening.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How many AI systems can take an action, not merely produce text.&lt;/strong&gt; A summarizer and an agent with write access to a ticketing system belong in different risk tiers. This number is your blast radius, and it is the one that most cleanly separates AI risk from ordinary vendor risk.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What fraction of AI vendor contracts carry data retention and training-use terms.&lt;/strong&gt; Legal usually has this and has never been asked to count it.&lt;/p&gt;

&lt;p&gt;Four numbers, each traceable to a system of record. That is a defensible briefing. A maturity score you cannot reconstruct under questioning is not.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three questions you will get
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Are we exposed?&lt;/em&gt; Answer with the inventory and egress numbers, then name the single largest concentration of risk rather than listing everything. Boards remember one thing.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Are we behind our peers?&lt;/em&gt; Resist the benchmark you cannot substantiate. What you can say honestly is which practices are becoming standard: an AI asset inventory, a documented approval gate, and contract terms covering retention and training use. Position against those, not against an invented industry percentile.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What will this cost?&lt;/em&gt; This is where briefings collapse, because the honest answer depends on a scope decision the board has not made. Present two or three scoped options with costs attached and let the board choose. Inventing a single number to sound decisive is how CISOs end up defending a figure they never believed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to leave out
&lt;/h2&gt;

&lt;p&gt;Framework recitation. Naming &lt;a href="https://www.nist.gov/itl/ai-risk-management-framework" rel="noopener noreferrer"&gt;NIST AI RMF&lt;/a&gt;, &lt;a href="https://www.iso.org/standard/81230.html" rel="noopener noreferrer"&gt;ISO/IEC 42001&lt;/a&gt;, and the &lt;a href="https://artificialintelligenceact.eu/" rel="noopener noreferrer"&gt;EU AI Act&lt;/a&gt; is fine as one line establishing that a structure exists. Walking a board through the four functions of the NIST framework is not a board conversation, and it reads as filling time.&lt;/p&gt;

&lt;p&gt;Threat theater, too. Deepfake fraud is real and directors will ask about it, but if it consumes more of your slot than your own deployment posture, the agenda came from the news rather than from your risk register. The same applies to technical attack detail: prompt injection is worth one clear sentence about why an AI assistant connected to internal documents is an exploitable path (&lt;a href="https://genai.owasp.org/llm-top-10/" rel="noopener noreferrer"&gt;OWASP LLM01&lt;/a&gt;, &lt;a href="https://atlas.mitre.org/techniques/AML.T0051" rel="noopener noreferrer"&gt;MITRE ATLAS AML.T0051&lt;/a&gt;), and not worth a diagram.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this structure does not apply
&lt;/h2&gt;

&lt;p&gt;It assumes you have an inventory. If you cannot say what AI is running in your environment, do not build a four-number deck on estimates. The correct briefing in that situation is short: state the gap, explain that everything else depends on closing it, and ask for a window and a budget. That version is uncomfortable to deliver and considerably more survivable than a dashboard that falls apart on the second question.&lt;/p&gt;

&lt;p&gt;It also assumes the board is engaged enough to decide something. A board that wants reassurance rather than decisions is a different problem, and a governance problem rather than a briefing problem.&lt;/p&gt;

&lt;p&gt;The judgment to hold this conversation is what the executive AI course we teach for security leaders is built around. For the underlying material, the posts on &lt;a href="https://dev.to/blog/ai-governance-training-security-executives"&gt;AI governance for security executives&lt;/a&gt; and &lt;a href="https://dev.to/blog/what-cisos-get-wrong-about-ai-risk"&gt;the AI risk blind spots CISOs miss&lt;/a&gt; go deeper. The &lt;a href="https://dev.to/courses/executive-ai-guide"&gt;one-day executive course&lt;/a&gt; works through it with other security leaders in the room, and if the board date is sooner than that, we also &lt;a href="https://dev.to/executive-briefing"&gt;brief leadership teams directly&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Tell if an AI Security Tool Actually Uses Real AI</title>
      <dc:creator>Charles Givre</dc:creator>
      <pubDate>Mon, 27 Jul 2026 17:11:00 +0000</pubDate>
      <link>https://dev.to/cgivre/how-to-tell-if-an-ai-security-tool-actually-uses-real-ai-3ff0</link>
      <guid>https://dev.to/cgivre/how-to-tell-if-an-ai-security-tool-actually-uses-real-ai-3ff0</guid>
      <description>&lt;p&gt;Ask a vendor whether their product uses machine learning and you will get a yes. Ask for the model architecture and you will get a slide. Neither answer tells you what is running in the detection path.&lt;/p&gt;

&lt;p&gt;You do not need the vendor's cooperation to find out. Four tests, run from outside the box on data you control, will tell you whether the thing scoring your events has learned parameters or is a weighted condition list with an AI label on the box. None of them require the vendor to open the model.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Rule Engine Is Not the Problem
&lt;/h2&gt;

&lt;p&gt;If a product scores an event by summing weights across 30 conditions, that can be a good detection engine. Rules are readable, predictable, and tunable by an analyst at 3 a.m. Plenty of detection problems should be solved that way.&lt;/p&gt;

&lt;p&gt;The problem is paying for a model and receiving rules. You get neither the generalization to unseen variants that a trained model buys you nor the transparency that makes a rule pack cheap to operate. So the question worth answering is narrow: does the scoring function have parameters that were fit to data, or thresholds that a person typed in?&lt;/p&gt;

&lt;h2&gt;
  
  
  Test 1: Count the Unique Scores
&lt;/h2&gt;

&lt;p&gt;You should already be insisting on raw per-detection output rather than dashboard counts as part of &lt;a href="https://dev.to/blog/how-to-run-poc-ai-security-vendor"&gt;POC discipline&lt;/a&gt;. That raw stream answers this question in one line of &lt;code&gt;pandas&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="n"&gt;scores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;vendor_detections.jsonl&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;risk_score&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nunique&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;unique values across&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;events&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value_counts&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;head&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A model with fit parameters produces a near-continuous distribution: hundreds or thousands of distinct values, most of them ugly decimals. A weighted rule engine produces a short repeating list, because every score is a sum over the same fixed condition set. Twelve unique values across 8,000 events is a rubric, not a model. Scores piling up on 25, 50, 75, and 90 point the same direction.&lt;/p&gt;

&lt;p&gt;The honest caveat: a vendor can bucket a real model's output before it reaches the API, which makes a genuine model look like a rubric. So treat low cardinality as a prompt to ask whether the pre-bucketing score is exposed, then run the next test, which bucketing cannot hide.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test 2: Sweep One Feature and Watch the Boundary
&lt;/h2&gt;

&lt;p&gt;This is the test that settles it. Take an event the product flags, vary a single field in small increments, resubmit each variant, and record the score.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;

&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;entropy&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;4.6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;synth_domain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entropy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;# your generator
&lt;/span&gt;        &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;length&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                     &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;entropy&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entropy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                     &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;vendor_api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;

&lt;span class="n"&gt;grid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;length&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;entropy&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read the surface. If the score is flat and then jumps in a vertical line at a round entropy value, identical for every domain length, a threshold fired. If the score rises gradually and the entropy at which it rises depends on the length, the scoring function learned an interaction between two features, which is something no analyst hand-codes.&lt;/p&gt;

&lt;p&gt;We teach this same procedure as the model-extraction lab on day four of the &lt;a href="https://dev.to/courses/applied-data-science-ai"&gt;Applied Data Science and AI for Cybersecurity&lt;/a&gt; course: query a black-box classifier through its API until the decision boundary becomes visible. The technique comes from the 2016 USENIX Security paper &lt;a href="https://www.usenix.org/conference/usenixsecurity16/technical-sessions/presentation/tramer" rel="noopener noreferrer"&gt;Stealing Machine Learning Models via Prediction APIs&lt;/a&gt;, and MITRE ATLAS catalogs the offensive version as &lt;a href="///atlas/AML.T0024.002"&gt;Extract AI Model (AML.T0024.002)&lt;/a&gt;. That matters procedurally: get written authorization and a rate limit agreed in advance, because a vendor's abuse detection will read a high-volume sweep exactly the way ATLAS describes it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test 3: Ask for the Version String, Not the Architecture
&lt;/h2&gt;

&lt;p&gt;Architecture answers cost a vendor nothing. Versioning is expensive to fake, because it only exists if someone built a pipeline. Ask for three artifacts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A model version in every detection payload.&lt;/strong&gt; &lt;code&gt;model_version: "url-clf-2026.06.3"&lt;/code&gt; on the detection itself, not the product release number in the footer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A retraining changelog.&lt;/strong&gt; Dates, and the held-out evaluation metrics for each version. Redaction is fine. Absence is the answer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The drift monitor.&lt;/strong&gt; What input distribution it watches, what threshold trips it, and what the team did the last time it tripped.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.nist.gov/itl/ai-risk-management-framework" rel="noopener noreferrer"&gt;NIST's AI Risk Management Framework&lt;/a&gt; (AI 100-1) puts exactly this under its MEASURE and MANAGE functions, so a vendor selling into regulated buyers has no excuse for being surprised by the request. The artifact to ask for by name is a model card, from &lt;a href="https://arxiv.org/abs/1810.03993" rel="noopener noreferrer"&gt;Model Cards for Model Reporting&lt;/a&gt; (Mitchell et al., 2019): intended use, training data, evaluation results, known failure modes. Teams running real models usually have something like it internally. A product that has "used ML since 2019" and cannot produce a single retraining date is not maintaining a model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test 4: Read What Actually Ships
&lt;/h2&gt;

&lt;p&gt;If any component runs in your environment, the inference stack is sitting on your disk. This is the fastest of the four and the hardest to spin.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;List the bundled runtime's dependencies for an inference library: &lt;code&gt;onnxruntime&lt;/code&gt;, &lt;code&gt;xgboost&lt;/code&gt;, &lt;code&gt;lightgbm&lt;/code&gt;, &lt;code&gt;torch&lt;/code&gt;, &lt;code&gt;scikit-learn&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Look for serialized weights: &lt;code&gt;find /opt/vendor -name '*.onnx' -o -name '*.pt' -o -name '*.pkl' -o -name '*.joblib'&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;strings&lt;/code&gt; and &lt;code&gt;ldd&lt;/code&gt; against native binaries for &lt;a href="https://onnxruntime.ai/" rel="noopener noreferrer"&gt;ONNX Runtime&lt;/a&gt; or libtorch symbols.&lt;/li&gt;
&lt;li&gt;Check egress. If the product claims local inference but the agent opens a connection to a scoring endpoint before every verdict, the model is not local, whatever the datasheet says.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The ratio is the finding. A 400 KB gradient-boosting model next to a 40,000-line YAML rule pack tells you which component does the work.&lt;/p&gt;

&lt;h2&gt;
  
  
  What These Tests Do Not Tell You
&lt;/h2&gt;

&lt;p&gt;None of this measures whether the product is any good. It measures whether one specific claim is true. A tuned rule pack from a vendor with deep threat-intel coverage will outperform a poorly trained model on your traffic, and for some vendors the rule pack is the genuinely valuable asset. Establish what the engine is so you can price it, then judge it on detection lift and false positive cost against your current stack.&lt;/p&gt;

&lt;p&gt;These four tests also do not transfer to LLM-wrapper products. When the "AI" is a hosted model behind a prompt, there is no decision boundary to sweep and score cardinality means nothing. The questions there are which model, what grounding, what happens to the output at temperature above zero, and whether the prompt is a trust boundary.&lt;/p&gt;

&lt;p&gt;Reading a score distribution and probing a decision boundary are ordinary data science skills, which is the point: the technical literacy to test a vendor claim is the same literacy that lets your team build detections. The &lt;a href="https://dev.to/courses/executive-ai-guide"&gt;executive AI course&lt;/a&gt; covers the decision side of this for security leaders, and the applied course is where analysts write the probe scripts themselves. Both sit inside GTK Cyber's &lt;a href="https://dev.to/lp/ai-cybersecurity-training"&gt;AI cybersecurity training&lt;/a&gt; track. For the questions to open the conversation with, start with our &lt;a href="https://dev.to/blog/evaluating-ai-security-vendors"&gt;vendor evaluation checklist&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Use Python and scikit-learn for Security Log Analysis</title>
      <dc:creator>Charles Givre</dc:creator>
      <pubDate>Wed, 22 Jul 2026 21:07:21 +0000</pubDate>
      <link>https://dev.to/cgivre/how-to-use-python-and-scikit-learn-for-security-log-analysis-4l0a</link>
      <guid>https://dev.to/cgivre/how-to-use-python-and-scikit-learn-for-security-log-analysis-4l0a</guid>
      <description>&lt;p&gt;scikit-learn shows up in most security ML tutorials as one thing: an anomaly detector. &lt;code&gt;IsolationForest&lt;/code&gt;, a contamination parameter, done. That is a fraction of what the library does for log data. Two other jobs matter more day to day in a SOC: grouping tens of thousands of near-identical log lines so an analyst reviews ten clusters instead of ten thousand events, and classifying events so known-benign noise stops paging anyone.&lt;/p&gt;

&lt;p&gt;This post covers those two workflows. It assumes you can already load a log into a DataFrame. If not, start with &lt;a href="https://dev.to/blog/pandas-for-security-data-analysis"&gt;Pandas for security data analysis&lt;/a&gt; and come back.&lt;/p&gt;

&lt;h2&gt;
  
  
  From log lines to a feature matrix
&lt;/h2&gt;

&lt;p&gt;scikit-learn models take a numeric matrix, not raw log text. Building that matrix is most of the work. Two encoders cover the majority of log fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Structured fields (port, bytes, status code, hour of day) go in as numbers, scaled with &lt;a href="https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.StandardScaler.html" rel="noopener noreferrer"&gt;&lt;code&gt;StandardScaler&lt;/code&gt;&lt;/a&gt; so no single large-magnitude column dominates.&lt;/li&gt;
&lt;li&gt;Free-text fields (URLs, process command lines, user agents, syslog messages) go through &lt;a href="https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html" rel="noopener noreferrer"&gt;&lt;code&gt;TfidfVectorizer&lt;/code&gt;&lt;/a&gt;, which turns text into weighted token vectors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a proxy log, that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.feature_extraction.text&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TfidfVectorizer&lt;/span&gt;

&lt;span class="c1"&gt;# df['url'] is the requested URL per row
&lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TfidfVectorizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;analyzer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;char_wb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ngram_range&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;min_df&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit_transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Character n-grams (&lt;code&gt;char_wb&lt;/code&gt;, 3 to 5 characters) work better than word tokens on URLs and command lines, where the signal lives in substrings like &lt;code&gt;/wp-admin&lt;/code&gt; or a base64 chunk, not in whitespace-separated words.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workflow 1: cluster to triage volume
&lt;/h2&gt;

&lt;p&gt;A single web server can emit tens of thousands of near-identical log lines an hour. Clustering collapses them. &lt;a href="https://scikit-learn.org/stable/modules/generated/sklearn.cluster.MiniBatchKMeans.html" rel="noopener noreferrer"&gt;&lt;code&gt;MiniBatchKMeans&lt;/code&gt;&lt;/a&gt; scales to large logs and groups the TF-IDF vectors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.cluster&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MiniBatchKMeans&lt;/span&gt;

&lt;span class="n"&gt;km&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MiniBatchKMeans&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n_clusters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;random_state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cluster&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;km&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit_predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Rare shapes hide in the smallest clusters
&lt;/span&gt;&lt;span class="n"&gt;sizes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cluster&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;value_counts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The move that pays off is sorting clusters by size and reviewing the smallest ones first. The giant clusters are your normal traffic. The cluster of 12 requests that resembles none of the other 49 clusters is the one worth an analyst's time. &lt;a href="https://scikit-learn.org/stable/modules/generated/sklearn.cluster.DBSCAN.html" rel="noopener noreferrer"&gt;&lt;code&gt;DBSCAN&lt;/code&gt;&lt;/a&gt; is an alternative when you do not want to pick &lt;code&gt;n_clusters&lt;/code&gt; up front, at the cost of tuning &lt;code&gt;eps&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is triage, not detection. Clustering tells you what is unusual in shape, not what is malicious. An analyst still reads the small clusters and makes the call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workflow 2: classify known event types
&lt;/h2&gt;

&lt;p&gt;Once you have labels (from past investigations, a SIEM's verdicts, or a public corpus), a supervised classifier can carry the repetitive decision. A &lt;a href="https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html" rel="noopener noreferrer"&gt;&lt;code&gt;RandomForestClassifier&lt;/code&gt;&lt;/a&gt; is a strong default on the mixed numeric-and-text features above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.ensemble&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RandomForestClassifier&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.model_selection&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;train_test_split&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.metrics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;classification_report&lt;/span&gt;

&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;train_test_split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;label&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;test_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stratify&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;label&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;random_state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;clf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RandomForestClassifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n_estimators&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;class_weight&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;balanced&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n_jobs&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;clf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;classification_report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two arguments earn their place. &lt;code&gt;class_weight='balanced'&lt;/code&gt; stops the model from predicting "benign" for everything when 99.9% of your logs are benign. &lt;code&gt;stratify=df['label']&lt;/code&gt; keeps the rare class present in both the train and test splits.&lt;/p&gt;

&lt;p&gt;The public &lt;a href="https://github.com/logpai/loghub" rel="noopener noreferrer"&gt;Loghub collection&lt;/a&gt; from the LogPAI group is a good place to practice. It has labeled system logs (HDFS, BGL, and others) with anomaly labels, so you can build and test a classifier without waiting for your own labeled incidents to pile up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the right metric
&lt;/h2&gt;

&lt;p&gt;Accuracy lies on security data. A classifier that calls everything benign scores 99.9% accuracy on a log where 1 in 1,000 events is malicious, and it catches nothing. Read precision and recall per class from &lt;code&gt;classification_report&lt;/code&gt;, and pick the tradeoff deliberately: a SOC drowning in alerts wants precision, a hunt for a known-bad pattern wants recall. For scoring outliers rather than known classes, that is the &lt;a href="https://dev.to/blog/anomaly-detection-security-operations"&gt;anomaly detection&lt;/a&gt; job, which uses a different family of models.&lt;/p&gt;

&lt;p&gt;The mistake we see most often when we teach this is students optimizing accuracy and declaring victory. On imbalanced security data that number is meaningless. We spend real lab time in the &lt;a href="https://dev.to/courses/applied-data-science-ai"&gt;Applied Data Science and AI for Cybersecurity&lt;/a&gt; course on reading a confusion matrix and choosing the metric that matches the mission, because it is the difference between a model that ships and one that quietly misses everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where scikit-learn stops
&lt;/h2&gt;

&lt;p&gt;scikit-learn is a batch library. It fits and predicts on data held in memory; it is not a streaming engine. For real-time scoring at SOC scale, you train in scikit-learn and then serve the fitted model behind your pipeline (a Kafka consumer, a Spark job, or a detection rule that calls the serialized model). Every model here also decays as traffic shifts: a classifier trained on last quarter's URLs slowly goes stale. Plan to retrain, and track precision and recall over time so you notice the drift before your analysts do.&lt;/p&gt;

&lt;p&gt;If you want reps on this with real security datasets, and an instructor who can tell you why a model did something surprising, that is what the &lt;a href="https://dev.to/lp/applied-data-science-black-hat-2026"&gt;Applied Data Science course at Black Hat USA 2026&lt;/a&gt; is built for.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A CISO's One Day at Black Hat: Inside the Executive AI Course</title>
      <dc:creator>Charles Givre</dc:creator>
      <pubDate>Tue, 21 Jul 2026 21:31:03 +0000</pubDate>
      <link>https://dev.to/cgivre/a-cisos-one-day-at-black-hat-inside-the-executive-ai-course-lp3</link>
      <guid>https://dev.to/cgivre/a-cisos-one-day-at-black-hat-inside-the-executive-ai-course-lp3</guid>
      <description>&lt;p&gt;The one-day executive AI course at Black Hat USA 2026 walks a security leader through four blocks in a single day: what AI really does for security, the governance frameworks that land on a CISO's desk, the AI-powered threats worth planning for, and how to evaluate the vendors selling into all of it. You leave able to interrogate a vendor, gate a deployment, and answer a board with specifics. No code, no labs.&lt;/p&gt;

&lt;p&gt;Black Hat USA 2026 runs August 1 to 4 at Mandalay Bay in Las Vegas. &lt;a href="https://dev.to/courses/executive-ai-guide"&gt;A Cyber Executive's Guide for Artificial Intelligence&lt;/a&gt; is the one-day option on August 3. Here is what that day actually looks like from the seat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Morning: what AI can and cannot do for security
&lt;/h2&gt;

&lt;p&gt;The day opens by separating the real from the sold. Every vendor deck claims AI. Most security leaders cannot yet tell a genuine capability from a demo built to survive a sales call. So the first block draws that line: where machine learning and large language models actually move the needle in detection, triage, and analysis, and where they quietly fail or add risk.&lt;/p&gt;

&lt;p&gt;This is not an AI theory lecture. It is the grounding a leader needs to walk into the next vendor meeting and ask a question the salesperson did not rehearse. By mid-morning you can hear a capability claim and know whether it is plausible, and just as important, you can tell your own team which AI ideas are worth piloting and which are hype dressed up in a roadmap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Late morning: governance frameworks that reach your desk
&lt;/h2&gt;

&lt;p&gt;The second block is the one CISOs ask for by name: governance. It covers the NIST AI Risk Management Framework as the operational backbone, the EU AI Act as the compliance overlay that applies to any organization with EU customers or operations, and how to map both onto the security and risk program you already run.&lt;/p&gt;

&lt;p&gt;The emphasis is practical, not a framework recital. Which controls map to which obligations. Where the gaps usually sit. What auditable evidence actually looks like when a regulator or a board asks. You leave this block able to tier AI risk in an inventory and gate new AI systems through an approval process, instead of signing policy you cannot enforce.&lt;/p&gt;

&lt;p&gt;If you want the deeper version of this material before you go, the post on &lt;a href="https://dev.to/blog/ai-governance-training-security-executives/"&gt;AI governance training for security executives&lt;/a&gt; covers the framework stack in detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Early afternoon: AI-powered threats, from the defender's chair
&lt;/h2&gt;

&lt;p&gt;After lunch the course turns to offense: how AI changes the threat model. Deepfakes in social engineering and fraud. Adversarial AI against the models you might deploy. AI-enabled attacks that scale what used to take a human. Prompt injection and RAG poisoning against the LLM assistants moving into enterprises now.&lt;/p&gt;

&lt;p&gt;The framing stays at the altitude a leader operates from: not how to write the exploit, but what the attack means for your risk register, your controls, and the questions you should be asking your own engineers. The companion read on &lt;a href="https://dev.to/blog/what-cisos-get-wrong-about-ai-risk/"&gt;AI risk blind spots CISOs miss&lt;/a&gt; covers several of these in more depth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Late afternoon: vendor evaluation and organizational readiness
&lt;/h2&gt;

&lt;p&gt;The final working block is where the day pays for itself. Vendor evaluation: how to question AI capability claims, what training-data and evaluation-methodology questions to ask, and how to design a proof of concept that produces evidence instead of a polished narrative. This is the skill that kills a bad six-figure contract before the renewal locks in.&lt;/p&gt;

&lt;p&gt;It closes on organizational readiness: what an AI-ready security program looks like, where the gaps usually are, and how to sequence the build. You leave with a picture of your own program's next three moves, not a generic maturity model.&lt;/p&gt;

&lt;p&gt;Two things make the room work. First, the material comes from working practitioners who have sat across the table from AI vendors and stood up governance inside real security programs, not from full-time trainers reading a deck. Executives can tell the difference, and the vendor-evaluation block in particular lands because it is drawn from decisions the instructors have actually made. Second, the peers in the seats next to you are other CISOs and senior security leaders wrestling with the same AI decisions, which is its own reason to be there. The hallway conversations at an executive course are frequently worth the trip on their own.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you walk out able to do
&lt;/h2&gt;

&lt;p&gt;By the end of the day the deliverable is judgment, not a binder. A CISO who took the course can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interrogate an AI vendor's claims and recognize a non-answer.&lt;/li&gt;
&lt;li&gt;Map an AI deployment to NIST AI RMF and the EU AI Act.&lt;/li&gt;
&lt;li&gt;Tier AI risk in an inventory and gate deployments through an approval process.&lt;/li&gt;
&lt;li&gt;Speak to AI risk in a board conversation with specifics instead of hand-waving.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is a full day at executive altitude, and it is the reason the format is one focused day rather than a week. If you are deciding whether to send a member of your leadership team, the companion post on &lt;a href="https://dev.to/blog/send-security-leaders-executive-ai-course-black-hat/"&gt;sending your security leaders&lt;/a&gt; works the budget and ROI side. For how the course fits with GTK's consulting and the CISO Brief, see the &lt;a href="https://dev.to/for-executives"&gt;for-executives hub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Full details and registration are on the &lt;a href="https://dev.to/courses/executive-ai-guide"&gt;executive course page&lt;/a&gt; and the &lt;a href="https://dev.to/lp/black-hat-2026-training"&gt;Black Hat 2026 training page&lt;/a&gt;. For a custom on-site version tailored to your regulatory environment and AI roadmap, &lt;a href="https://dev.to/contact"&gt;contact us&lt;/a&gt;. The seat is one day; the decisions it improves run for years.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Should You Send Your Security Leaders to an Executive AI Course?</title>
      <dc:creator>Charles Givre</dc:creator>
      <pubDate>Tue, 21 Jul 2026 21:30:49 +0000</pubDate>
      <link>https://dev.to/cgivre/should-you-send-your-security-leaders-to-an-executive-ai-course-3p52</link>
      <guid>https://dev.to/cgivre/should-you-send-your-security-leaders-to-an-executive-ai-course-3p52</guid>
      <description>&lt;p&gt;If a member of your security leadership signs off on AI purchases or AI deployment risk, one day at Black Hat USA 2026 is worth the seat. A Cyber Executive's Guide for Artificial Intelligence runs August 3 in Las Vegas, and it pays for itself the first time a CISO kills a weak AI vendor deal or governs a deployment correctly instead of approving it blind.&lt;/p&gt;

&lt;p&gt;Most AI training aimed at executives is generic: business applications across industries, a tour of what large language models can do, a few slides on ethics. That is not what a security leader needs. A CISO needs to reason about AI-powered threats, govern AI deployed inside a security program, and answer for it when a regulator or a board asks. This course is built for that person specifically.&lt;/p&gt;

&lt;h2&gt;
  
  
  The decision this course actually improves
&lt;/h2&gt;

&lt;p&gt;The expensive AI mistakes at the executive level are not technical. They are decisions made without enough literacy to ask the right questions.&lt;/p&gt;

&lt;p&gt;A vendor demos an AI-powered detection tool. It looks impressive. Nobody in the room knows to ask what the model was trained on, how it was evaluated, or what the false positive rate looks like on data that resembles your environment. The contract gets signed. Six months later the tool is generating noise and the renewal is already locked in.&lt;/p&gt;

&lt;p&gt;Or: a team wants to deploy an internal LLM assistant with access to ticketing and email. It ships. Nobody scoped prompt injection through retrieved content, agent tool permissions, or data provenance. The blind spot becomes an incident.&lt;/p&gt;

&lt;p&gt;The course targets exactly these moments. Not by making executives into engineers, but by giving them enough technical judgment to interrogate a vendor claim, recognize a non-answer, and gate a deployment on real evidence. That is the skill that carries budget authority.&lt;/p&gt;

&lt;h2&gt;
  
  
  What one day covers
&lt;/h2&gt;

&lt;p&gt;The day is organized around the decisions a security executive makes, not around AI theory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What AI can and cannot do for security.&lt;/strong&gt; The real capabilities and the real limits, so you can tell a genuine use case from a demo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Risk and governance frameworks.&lt;/strong&gt; NIST AI Risk Management Framework, the EU AI Act and its high-risk system obligations, and how to map both onto the security and compliance program you already run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI-powered threats.&lt;/strong&gt; Deepfakes, adversarial AI, and AI-enabled attacks, framed from a defender's perspective.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vendor evaluation.&lt;/strong&gt; How to question AI capability claims, what training-data and evaluation-methodology questions to ask, and how to design a proof of concept that produces evidence instead of a sales narrative.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Organizational readiness.&lt;/strong&gt; What an AI-ready security organization looks like, and where the gaps usually are.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is decision-grade content with no technical prerequisites. The goal is that an executive leaves able to ask specific questions and act on the answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the one-day format works
&lt;/h2&gt;

&lt;p&gt;A common objection: can a single day cover enough to matter? For executive decision-making, yes, because the target is judgment, not implementation. An engineer needs weeks of lab time to build and test models. A leader needs enough grounding to govern the people who do, evaluate the vendors who sell to them, and defend the decisions to a board.&lt;/p&gt;

&lt;p&gt;One focused day at that altitude is the right dose. It also fits an executive calendar in a way a four-day technical course never will, which is part of why it is the format that actually gets attended.&lt;/p&gt;

&lt;p&gt;The instructors matter here too. GTK Cyber courses are taught by working practitioners, not full-time trainers, so the vendor-evaluation and governance material comes from people who have actually sat across the table from AI vendors and stood up governance inside real security programs. Executives can tell the difference between a slide deck and someone describing a decision they have made. That credibility is what makes an executive room engage instead of tune out.&lt;/p&gt;

&lt;h2&gt;
  
  
  The math on sending someone
&lt;/h2&gt;

&lt;p&gt;Price the course against your training budget. Price the decisions it improves against your risk register. Those are different orders of magnitude.&lt;/p&gt;

&lt;p&gt;One AI vendor contract questioned hard enough to walk away from a bad fit. One deployment governed correctly the first time. One board conversation where your CISO can speak to AI risk with specifics instead of hand-waving. Any one of those outcomes returns the cost of a seat and the travel around it.&lt;/p&gt;

&lt;p&gt;If you have several leaders who should hear this, the math shifts again. GTK Cyber delivers the same material as a custom on-site program tailored to your regulatory environment and AI roadmap. For a leadership team or a board, an on-site engagement is usually more cost-effective than sending each person to Las Vegas, and it can be scheduled around your calendar instead of Black Hat's. &lt;a href="https://dev.to/contact"&gt;Contact us&lt;/a&gt; to scope one.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it fits the rest of the program
&lt;/h2&gt;

&lt;p&gt;Black Hat USA 2026 is August 1-4 at Mandalay Bay. The executive course is one day on August 3, which leaves room to pair it with the conference itself or to send technical staff to one of GTK Cyber's hands-on courses running the same week.&lt;/p&gt;

&lt;p&gt;If you are weighing which course fits which person on your team, the &lt;a href="https://dev.to/blog/which-gtk-black-hat-course-is-right/"&gt;course decision guide&lt;/a&gt; matches each of the three GTK Cyber Black Hat courses to role and time budget. For the executive path specifically, the &lt;a href="https://dev.to/for-executives"&gt;for-executives hub&lt;/a&gt; lays out how the course, consulting, and the CISO Brief fit together. Full course details and registration are on the &lt;a href="https://dev.to/courses/executive-ai-guide"&gt;executive course page&lt;/a&gt; and the &lt;a href="https://dev.to/lp/black-hat-2026-training"&gt;Black Hat 2026 training page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The security leaders who govern AI well over the next two years will be the ones who built the judgment early. One day in Las Vegas is a cheap place to start.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What You Build in the 4-Day AI Cyber Bootcamp at Black Hat</title>
      <dc:creator>Charles Givre</dc:creator>
      <pubDate>Tue, 21 Jul 2026 14:16:36 +0000</pubDate>
      <link>https://dev.to/cgivre/what-you-build-in-the-4-day-ai-cyber-bootcamp-at-black-hat-10h1</link>
      <guid>https://dev.to/cgivre/what-you-build-in-the-4-day-ai-cyber-bootcamp-at-black-hat-10h1</guid>
      <description>&lt;p&gt;Four days in the AI Cyber Bootcamp at Black Hat USA 2026 produce a folder of working notebooks: trained detection models, an anomaly-hunting pipeline, an LLM triage workflow, and an AI agent that automates a SOC task. You write the code in labs on real security data, and it runs in your own environment after you leave. The point is not to watch a demo. It is to build the thing.&lt;/p&gt;

&lt;p&gt;Black Hat USA 2026 runs August 1 to 4 at Mandalay Bay in Las Vegas. The bootcamp is the &lt;a href="https://dev.to/courses/ai-cyber-bootcamp"&gt;four-day AI Cyber Bootcamp&lt;/a&gt; and takes all four training days. Here is what each stretch of the course actually puts in your hands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Foundations: data science on real security data
&lt;/h2&gt;

&lt;p&gt;You start with the unglamorous part that everything else depends on: getting security data into a shape a model can use. Pandas and Python against real datasets (PCAP-derived features, EDR telemetry, phishing corpora, malware metadata), not toy CSVs. You do the preprocessing, feature engineering, and exploratory analysis that decide whether a model works or wastes a week.&lt;/p&gt;

&lt;p&gt;By the end of the first stretch you have a clean feature pipeline you built yourself, and you understand why a model failed when the features were wrong. That skill transfers to every detection problem you will ever touch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Classical ML for detection you can defend
&lt;/h2&gt;

&lt;p&gt;Next you train supervised models on problems analysts actually see: malware family classification, phishing detection, intrusion classification, SOC alert triage. You work through Random Forest, Naive Bayes, KNN, and SVM, and more importantly you learn when to reach for which one and how to read the evaluation honestly.&lt;/p&gt;

&lt;p&gt;This is where the FAQ question everyone asks gets answered in code: Random Forest handles mixed features, non-linear interactions, and gives you feature importance, which makes it a strong default for malware and intrusion work. Naive Bayes trains fast on sparse text features for spam. You do not take that on faith. You train both, compare the confusion matrices, and see it.&lt;/p&gt;

&lt;p&gt;The output is a set of trained, evaluated classifiers with metrics you can explain to a skeptical senior analyst. That is the difference between a model you deploy and a model you hope works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unsupervised learning for threat hunting
&lt;/h2&gt;

&lt;p&gt;Detection assumes you know what you are looking for. Hunting does not. So the course moves into unsupervised methods: KMeans and hierarchical clustering to group similar users, hosts, and processes; DBSCAN and IsolationForest for anomaly detection; PCA and t-SNE to explore high-dimensional data you cannot eyeball.&lt;/p&gt;

&lt;p&gt;The labs run these against authentication logs, network flow, and EDR telemetry, so what you build is a hunting pipeline that surfaces the odd account, the anomalous host, the process that does not fit. You leave with a notebook that turns a pile of logs into a ranked list of things worth investigating.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generative AI and agents that do real work
&lt;/h2&gt;

&lt;p&gt;The back half turns to LLMs and agents. You use a language model for the tasks it is genuinely good at: summarizing threat intel, drafting log analysis, triaging alerts. You practice prompt engineering as an evaluated skill, not a party trick, measuring whether a prompt actually improves the output on a security task.&lt;/p&gt;

&lt;p&gt;Then you build an AI agent that automates a SOC workflow end to end. This is the piece students most often tell us changed how they think about their job: an agent that reads, decides, and calls tools, doing the repetitive analysis a human was burning hours on. You walk out with the agent code and a clear sense of where agents help and where they quietly go wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adversarial AI: attack the models you just built
&lt;/h2&gt;

&lt;p&gt;The course does not let you deploy AI without understanding how it breaks. The final labs are red and blue team exercises against ML and LLM systems: model evasion, data poisoning, prompt injection, and RAG poisoning, the attack that matters most now that nearly every enterprise LLM deployment grounds answers in a retrieval corpus.&lt;/p&gt;

&lt;p&gt;You attack models like the ones you trained earlier in the week, then defend them. That loop is the whole reason to learn AI and security together instead of separately. You leave able to reason about the attack surface of an AI system, not just its accuracy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you take home
&lt;/h2&gt;

&lt;p&gt;Add it up and the four days produce a working portfolio, not a certificate to frame: trained classifiers with honest evaluation, a clustering and anomaly-detection hunting pipeline, an LLM triage workflow, a SOC-automation agent, and a set of adversarial exercises you have run from both sides. All of it lab-built on the Centaur VM and real security data, all of it runnable in your own environment on the flight home. Most students are using at least one of those notebooks in production within a month. That is the test of training that worked: code you keep and use, not notes you never open again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should take it, and who should not
&lt;/h2&gt;

&lt;p&gt;The bootcamp is built for security professionals who can read code and want to apply AI, ML, and data science to operations. Analysts, detection engineers, and threat hunters are the sweet spot. If you have never written a script, the pace will hurt.&lt;/p&gt;

&lt;p&gt;If you are a security leader who needs to govern AI rather than build it, the four-day technical course is the wrong seat. The one-day &lt;a href="https://dev.to/for-executives"&gt;executive course&lt;/a&gt; covers risk, governance, and vendor evaluation for that audience instead. Not sure which fits your team? The &lt;a href="https://dev.to/blog/which-gtk-black-hat-course-is-right/"&gt;course decision guide&lt;/a&gt; matches each GTK Black Hat course to role and time. For a group or a custom on-site version, &lt;a href="https://dev.to/contact"&gt;contact us&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Full details and registration are on the &lt;a href="https://dev.to/lp/black-hat-2026-training"&gt;Black Hat 2026 training page&lt;/a&gt;. The seats that matter fill early; the folder of working code is worth booking one.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>cybersecurity</category>
      <category>learning</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Hands-On vs Lecture-Based Cybersecurity Training: Which Builds Skills</title>
      <dc:creator>Charles Givre</dc:creator>
      <pubDate>Fri, 17 Jul 2026 14:02:41 +0000</pubDate>
      <link>https://dev.to/cgivre/hands-on-vs-lecture-based-cybersecurity-training-which-builds-skills-573e</link>
      <guid>https://dev.to/cgivre/hands-on-vs-lecture-based-cybersecurity-training-which-builds-skills-573e</guid>
      <description>&lt;p&gt;If you are buying training for a security team, the format matters more than the syllabus. Two courses can cover the same MITRE ATT&amp;amp;CK techniques, the same detection methods, the same tools, and produce completely different results depending on whether your people spent the week watching or doing.&lt;/p&gt;

&lt;p&gt;The marketing does not help. Nearly every vendor now calls their training "hands-on." Some of it is. A lot of it is a lecture with a screen share.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Research Actually Says
&lt;/h2&gt;

&lt;p&gt;Skip the "learning pyramid" you have seen on a hundred slides, the one claiming people remember 10% of what they read and 90% of what they do. Those numbers have no empirical source. They were fabricated and repeated until they looked like fact.&lt;/p&gt;

&lt;p&gt;The real evidence is better and more specific. A 2014 meta-analysis of 225 studies across STEM education (&lt;a href="https://doi.org/10.1073/pnas.1319030111" rel="noopener noreferrer"&gt;Freeman et al., PNAS&lt;/a&gt;) found that active learning cut exam failure rates from 33.8% under traditional lecturing to 21.8%, and improved exam scores by roughly 0.47 standard deviations. The authors noted that if these had been drug trials, the results would have justified stopping the study early to switch everyone to the better treatment.&lt;/p&gt;

&lt;p&gt;Retention is the other half. The Ebbinghaus forgetting curve describes how quickly memory of new material decays without retrieval practice. A lecture is pure exposure. A lab forces retrieval and application, which is why the skills stick.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security Skills Are Procedural, Not Declarative
&lt;/h2&gt;

&lt;p&gt;Here is the part specific to our field. Most of what a security professional needs to learn is procedural knowledge: how to do something, not what something is.&lt;/p&gt;

&lt;p&gt;You can memorize the definition of an isolation forest from a slide. That does not mean you can pick features from an auth log, set &lt;code&gt;contamination&lt;/code&gt; sensibly, read the raw anomaly scores, and decide which flagged events are worth an analyst's time. You can watch someone explain &lt;a href="https://dev.to/blog/prompt-injection-explained"&gt;prompt injection&lt;/a&gt;. That does not mean you can craft a payload that bypasses a system prompt. You can hear about C2 beaconing. Detecting it in your own &lt;a href="https://zeek.org/" rel="noopener noreferrer"&gt;Zeek&lt;/a&gt; &lt;code&gt;conn.log&lt;/code&gt; is a different skill entirely, as our walkthrough on &lt;a href="https://dev.to/blog/hunting-c2-beaconing-python"&gt;hunting C2 beaconing with Python&lt;/a&gt; shows.&lt;/p&gt;

&lt;p&gt;Procedural skills are acquired through reps. There is no shortcut, and watching an expert do it is not a rep.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Lab-Based Training Looks Like
&lt;/h2&gt;

&lt;p&gt;Real hands-on security training puts the student in a live environment against realistic data and asks them to produce something. A few concrete examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Detection engineering.&lt;/strong&gt; Write a &lt;a href="https://github.com/SigmaHQ/sigma" rel="noopener noreferrer"&gt;Sigma&lt;/a&gt; rule, then test it against emulated adversary behavior from &lt;a href="https://github.com/redcanaryco/atomic-red-team" rel="noopener noreferrer"&gt;Atomic Red Team&lt;/a&gt; or &lt;a href="https://github.com/mitre/caldera" rel="noopener noreferrer"&gt;MITRE Caldera&lt;/a&gt;. A rule that fires on &lt;code&gt;T1059.001&lt;/code&gt; PowerShell execution is easy to write and easy to get wrong:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;detection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;selection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Image|endswith&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\powershell.exe'&lt;/span&gt;
      &lt;span class="na"&gt;CommandLine|contains&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-enc'&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;FromBase64String'&lt;/span&gt;
    &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;selection&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You only learn where that rule produces false positives by running it against real telemetry.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Applied ML for detection.&lt;/strong&gt; Load logs into a &lt;a href="https://pandas.pydata.org/" rel="noopener noreferrer"&gt;pandas&lt;/a&gt; DataFrame in &lt;a href="https://jupyter.org/" rel="noopener noreferrer"&gt;Jupyter&lt;/a&gt;, engineer features, fit a model from &lt;a href="https://scikit-learn.org/" rel="noopener noreferrer"&gt;scikit-learn&lt;/a&gt;, and evaluate it on held-out data. The evaluation step, precision versus recall on your own data, is where the learning happens.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AI red-teaming.&lt;/strong&gt; Run prompt injection and jailbreak payloads against a local model with &lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;, then scan it systematically with &lt;a href="https://github.com/NVIDIA/garak" rel="noopener noreferrer"&gt;garak&lt;/a&gt;. Our &lt;a href="https://dev.to/blog/ai-red-teaming-tips-for-beginners"&gt;prompt injection lab&lt;/a&gt; works exactly this way.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In every case the student walks away with an artifact: a working notebook, a tested rule, a documented finding. That is the tell. If the deliverable is a completed slide deck, it was a lecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Lectures Still Earn Their Place
&lt;/h2&gt;

&lt;p&gt;Format should match the goal. Lectures are the right tool when the objective is understanding rather than muscle memory. An executive AI risk briefing, a governance framework walkthrough, a threat modeling discussion, an introduction to an unfamiliar domain: these are conceptual, and structured lecture plus discussion works well. Our &lt;a href="https://dev.to/courses/executive-ai-guide"&gt;executive AI training&lt;/a&gt; is deliberately built this way, because a CISO needs to make good decisions, not tune a classifier.&lt;/p&gt;

&lt;p&gt;The failure mode is using lecture format to teach a skill. No amount of watching someone build a detection pipeline builds one in your team's hands.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Vet a Vendor's "Hands-On" Claim
&lt;/h2&gt;

&lt;p&gt;Since most vendors claim hands-on, make them prove it. Ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What percentage of class time is students in a lab versus watching the instructor?&lt;/li&gt;
&lt;li&gt;What environment do the labs run on, and do students keep access after the course?&lt;/li&gt;
&lt;li&gt;Can you see a sample exercise, and what artifact does the student produce?&lt;/li&gt;
&lt;li&gt;Does every student get their own environment, or does the instructor drive while everyone watches?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A vendor running genuine labs answers these easily. One that dodges them is selling a presentation.&lt;/p&gt;

&lt;p&gt;GTK Cyber's courses run on a proprietary lab platform where every student works in their own environment against real security data, taught by practitioners who do this work. The &lt;a href="https://dev.to/courses/applied-data-science-ai"&gt;Applied Data Science and AI for Cybersecurity&lt;/a&gt; course and the &lt;a href="https://dev.to/courses/ai-cyber-bootcamp"&gt;AI Cyber Bootcamp&lt;/a&gt; are built around exercises, not slides. If you are evaluating training for your team, ask us to show you a lab.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>AI Governance Training for Security Executives: What to Learn</title>
      <dc:creator>Charles Givre</dc:creator>
      <pubDate>Thu, 16 Jul 2026 13:40:14 +0000</pubDate>
      <link>https://dev.to/cgivre/ai-governance-training-for-security-executives-what-to-learn-4mh4</link>
      <guid>https://dev.to/cgivre/ai-governance-training-for-security-executives-what-to-learn-4mh4</guid>
      <description>&lt;p&gt;Most AI governance training for executives teaches people to recite framework names. NIST AI RMF, the EU AI Act, ISO 42001. That is not governance. Governance is the operational capability to decide which AI systems your organization deploys, on what data, and with what controls, and to enforce that decision. Training that does not build that capability produces executives who can sign a policy but cannot tell whether the deployment in front of them is safe.&lt;/p&gt;

&lt;p&gt;Here is what AI governance training for security leaders should actually cover.&lt;/p&gt;

&lt;h2&gt;
  
  
  What AI Governance Means for a Security Leader
&lt;/h2&gt;

&lt;p&gt;Strip away the framework vocabulary and governance comes down to three decisions, made repeatedly, for every AI system in the environment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What gets deployed. A marketing chatbot, a code assistant with repository access, and an autonomous agent with write permissions carry very different risk. Governance decides which ones proceed and under what conditions.&lt;/li&gt;
&lt;li&gt;On what data. The single biggest AI exposure most organizations have is sensitive data flowing into systems with unclear retention and training policies. Governance sets what data classes are allowed into which systems.&lt;/li&gt;
&lt;li&gt;With what controls. Logging, human-in-the-loop review, permission scoping, and monitoring. Governance defines the minimum bar before a system goes live.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this is new to a security leader. It is the same asset inventory, risk tiering, and approval-gate discipline you already apply to software and vendors. The difference is that AI systems fail in ways traditional software does not, and the controls have to account for that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Framework Stack Worth Knowing
&lt;/h2&gt;

&lt;p&gt;Executives do not need to memorize these. They need to know what each one does and where it fits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.nist.gov/itl/ai-risk-management-framework" rel="noopener noreferrer"&gt;NIST AI RMF&lt;/a&gt;&lt;/strong&gt; (document AI 100-1) is the operational backbone for most US organizations. It structures AI risk work into four functions: Govern, Map, Measure, and Manage. The companion Generative AI Profile (NIST-AI-600-1, published July 2024) adds specific guidance for LLM and generative systems. It is voluntary and gives you a vocabulary and process, not a compliance checklist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.iso.org/standard/81230.html" rel="noopener noreferrer"&gt;ISO/IEC 42001:2023&lt;/a&gt;&lt;/strong&gt; is the AI management system standard. Think of it as ISO 27001 for AI: it is certifiable and auditable, which matters when a customer or regulator wants evidence that your AI governance is a system, not a slide deck. ISO/IEC 23894:2023 is the companion AI risk management guidance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://artificialintelligenceact.eu/" rel="noopener noreferrer"&gt;The EU AI Act&lt;/a&gt;&lt;/strong&gt; (Regulation (EU) 2024/1689) is the regulatory obligation. It sorts AI systems into risk tiers: prohibited, high-risk, limited-risk, and minimal-risk. Timelines matter: it entered into force in August 2024, prohibited practices applied from February 2025, general-purpose AI model obligations from August 2025, and most high-risk obligations from August 2026. It applies extraterritorially, so a US company with EU customers is in scope.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://genai.owasp.org/llm-top-10/" rel="noopener noreferrer"&gt;OWASP Top 10 for LLM Applications&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href="https://atlas.mitre.org/" rel="noopener noreferrer"&gt;MITRE ATLAS&lt;/a&gt;&lt;/strong&gt; cover the technical control side. OWASP LLM01 is prompt injection; the list maps the concrete failure modes of deployed LLM systems. ATLAS catalogs adversarial techniques against ML systems, including LLM prompt injection (AML.T0051) and training-data poisoning (AML.T0020). These are what turn a governance policy into specific controls a security team can test.&lt;/p&gt;

&lt;p&gt;The mistake to avoid is treating these as interchangeable. NIST AI RMF is the operational process. ISO 42001 is the auditable system. The EU AI Act is the law. OWASP and ATLAS are the threat and control vocabulary. Governance training should teach the relationship, not the list.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a Governance Program Actually Produces
&lt;/h2&gt;

&lt;p&gt;A governance function that works produces artifacts, not intentions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;An AI asset inventory.&lt;/strong&gt; Every AI system in the environment, including embedded vendor features and developer tooling (GitHub Copilot, Cursor, internal OpenAI or Anthropic API keys). Most organizations cannot produce this today, and it is the prerequisite for everything else.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A model risk tiering scheme.&lt;/strong&gt; A rubric that sorts systems by data sensitivity, autonomy, and blast radius so a low-risk summarizer and a high-risk agent get proportionate review.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An acceptable-use policy with technical enforcement.&lt;/strong&gt; Not an awareness memo. A data-classification-backed rule that DLP tooling (Microsoft Purview, Netskope, Zscaler) can enforce.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An approval gate.&lt;/strong&gt; A cross-functional review with actual authority to stop a deployment, so a business unit cannot ship an AI feature on live customer data without security sign-off.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Third-party AI contract terms.&lt;/strong&gt; Clauses covering data retention, training use, prompt-injection resilience, and inference-time isolation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a governance program is not producing these, it is producing paperwork.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Technical Literacy the Role Requires
&lt;/h2&gt;

&lt;p&gt;This is where most executive AI training falls short. Governance without technical literacy becomes rubber-stamping. An executive who cannot reason about how &lt;a href="https://dev.to/blog/prompt-injection-explained"&gt;prompt injection&lt;/a&gt; exfiltrates data through an agent's tool calls, or why a model trained on unvetted data is a supply chain risk, will approve systems on the strength of a vendor's reassurance.&lt;/p&gt;

&lt;p&gt;The bar is not a data science degree. It is enough understanding to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ask an AI vendor specific questions and recognize a non-answer. Our &lt;a href="https://dev.to/blog/evaluating-ai-security-vendors"&gt;AI security vendor evaluation checklist&lt;/a&gt; covers the technical questions worth asking.&lt;/li&gt;
&lt;li&gt;Understand why an agent with broad tool permissions is a larger attack surface than a read-only assistant, and insist on least privilege.&lt;/li&gt;
&lt;li&gt;Read an evaluation result and know whether the reported accuracy means anything for your environment.&lt;/li&gt;
&lt;li&gt;Recognize which &lt;a href="https://dev.to/blog/what-cisos-get-wrong-about-ai-risk"&gt;AI risks are already in the building&lt;/a&gt; versus which are speculative.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That literacy is what separates governing AI from signing off on policies your team wrote.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to Get the Training
&lt;/h2&gt;

&lt;p&gt;GTK Cyber's executive course, &lt;a href="https://dev.to/courses/executive-ai-guide"&gt;A Cyber Executive's Guide for Artificial Intelligence&lt;/a&gt;, is built for exactly this: security leaders who need to govern AI deployments and understand the frameworks well enough to make defensible decisions. It covers the risk and governance stack above, the regulatory environment, and how to build an AI-ready security organization, without turning executives into data scientists. It runs at Black Hat USA 2026 and as a custom on-site program. Executives who want the strategic and governance context for their whole leadership team can also look at our &lt;a href="https://dev.to/lp/ai-training-for-cisos"&gt;AI training for CISOs&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Using LLMs for Log Analysis: Parsing, Clustering, and Queries</title>
      <dc:creator>Charles Givre</dc:creator>
      <pubDate>Mon, 13 Jul 2026 14:05:02 +0000</pubDate>
      <link>https://dev.to/cgivre/using-llms-for-log-analysis-parsing-clustering-and-queries-3350</link>
      <guid>https://dev.to/cgivre/using-llms-for-log-analysis-parsing-clustering-and-queries-3350</guid>
      <description>&lt;p&gt;An LLM will not read your logs for you. It cannot, at least not the way vendors imply: a single busy host emits millions of lines a day, and no model context window or API budget survives that volume. The teams getting value from large language models in log analysis are the ones who reduce the data with deterministic tooling first, then point the model at the language-heavy remainder.&lt;/p&gt;

&lt;p&gt;Here is the split that works, the tools to use, and where it breaks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reduce Before You Reason
&lt;/h2&gt;

&lt;p&gt;The first mistake is treating the model as the parser. It is the last step, not the first. Before an LLM sees anything, collapse the raw stream into a small set of representatives.&lt;/p&gt;

&lt;p&gt;For high-volume structured-ish logs (auth, web, firewall), mine templates with &lt;a href="https://github.com/logpai/Drain3" rel="noopener noreferrer"&gt;Drain3&lt;/a&gt;. It groups lines by their fixed skeleton and treats the variable parts as parameters, with no training required. Millions of lines become a few hundred templates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;drain3&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TemplateMiner&lt;/span&gt;

&lt;span class="n"&gt;miner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TemplateMiner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/var/log/auth.log&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;miner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_log_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="c1"&gt;# A few hundred templates instead of millions of raw lines
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;cluster&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;miner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clusters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_template&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you have something a model can actually work with: send the templates, their counts, and a few example lines, and ask the model to label each cluster, flag which ones are security-relevant, and group them by activity. You are spending tokens on a few hundred patterns, not tens of millions of events.&lt;/p&gt;

&lt;h2&gt;
  
  
  Force Structured Output on the Messy Tail
&lt;/h2&gt;

&lt;p&gt;Drain3 and Grok patterns handle the regular logs cheaply. The long tail is where the model earns its keep: free-text error messages, vendor appliance logs with no schema, application exceptions that never look the same twice.&lt;/p&gt;

&lt;p&gt;Do not ask for prose back. Force a schema, the same way you would for any other enrichment callout. On the &lt;a href="https://docs.anthropic.com/en/api/messages" rel="noopener noreferrer"&gt;Anthropic Messages API&lt;/a&gt;, tool use doubles as a structured-output contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;anthropic&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anthropic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Anthropic&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# reads ANTHROPIC_API_KEY
&lt;/span&gt;
&lt;span class="n"&gt;extract_tool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;extract_log_fields&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Extract normalized fields from a single unstructured log line.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input_schema&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;properties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;event_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src_ip&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;username&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;outcome&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;enum&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;failure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;severity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;enum&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;info&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;low&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;required&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;event_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;outcome&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-haiku-4-5-20251001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;# cheap model for high-volume work
&lt;/span&gt;    &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;extract_tool&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;tool_choice&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;extract_log_fields&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Extract only fields present in the line. Do not invent values.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;raw_line&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_use&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;enum&lt;/code&gt; constraints stop the model from inventing a new severity, and you validate every returned &lt;code&gt;src_ip&lt;/code&gt; against an IPv4/IPv6 format before it enters your store. Route this high-volume extraction to a cheap model like Claude Haiku 4.5 (&lt;code&gt;claude-haiku-4-5-20251001&lt;/code&gt;); save the expensive models for the investigations a human already cares about. The same routing-by-severity logic applies here as in a full &lt;a href="https://dev.to/blog/how-to-integrate-chatgpt-or-claude-into-a-soc"&gt;SOC integration&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cluster With Embeddings, Not Prompts
&lt;/h2&gt;

&lt;p&gt;Two log lines can describe the same event with completely different wording. Embeddings catch that where string matching does not. Embed each message with a small local sentence-transformer, then cluster the vectors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sentence_transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SentenceTransformer&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.cluster&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DBSCAN&lt;/span&gt;

&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SentenceTransformer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;all-MiniLM-L6-v2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# runs locally, no data leaves
&lt;/span&gt;&lt;span class="n"&gt;vectors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;normalize_embeddings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;labels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DBSCAN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;min_samples&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;metric&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cosine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fit_predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vectors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# label == -1 marks the outliers worth an analyst's attention
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the embedding model locally with &lt;a href="https://www.sbert.net/" rel="noopener noreferrer"&gt;sentence-transformers&lt;/a&gt; so you are not paying per token or exporting logs to analyze them. Store the vectors in &lt;a href="https://github.com/pgvector/pgvector" rel="noopener noreferrer"&gt;pgvector&lt;/a&gt; and you get "show me logs similar to this one" during an investigation. The &lt;code&gt;-1&lt;/code&gt; outliers from &lt;a href="https://scikit-learn.org/stable/modules/generated/sklearn.cluster.DBSCAN.html" rel="noopener noreferrer"&gt;&lt;code&gt;DBSCAN&lt;/code&gt;&lt;/a&gt; are the rare events; hand only those to the LLM for explanation. This is the same feature-then-model discipline covered in &lt;a href="https://dev.to/blog/feature-engineering-security-machine-learning"&gt;feature engineering for security data&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Draft Queries, Do Not Run Them
&lt;/h2&gt;

&lt;p&gt;Turning an analyst's plain-English intent into first-draft Splunk SPL, KQL, or a &lt;a href="https://github.com/SigmaHQ/sigma" rel="noopener noreferrer"&gt;Sigma&lt;/a&gt; rule is a real win. Generating a query and running it unattended is not. Models invent field names that do not exist in your schema, botch time-window boundaries, and write queries that look correct while matching the wrong events.&lt;/p&gt;

&lt;p&gt;Give the model your actual field list so it stops guessing, and treat the output like generated code: review it, run it against a bounded time range, and sanity-check the hit count before it becomes a scheduled detection. A generated query that returns zero results or ten million both mean the same thing: read it before you trust it. This is the reverse of the &lt;a href="https://dev.to/blog/siem-to-jupyter-detection-workflow"&gt;SIEM-to-Jupyter workflow&lt;/a&gt;, where the analyst writes the logic and the notebook keeps it reproducible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where It Breaks
&lt;/h2&gt;

&lt;p&gt;Plan for these from the first prototype:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Aggregation belongs in SQL.&lt;/strong&gt; Counting failed logins per user across a week is a &lt;code&gt;GROUP BY&lt;/code&gt;, not a prompt. Models cannot count reliably at scale and will confidently give you a wrong total.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log fields are attacker-controlled.&lt;/strong&gt; A User-Agent, a filename, an HTTP path can carry an indirect prompt injection (OWASP &lt;a href="https://genai.owasp.org/llm-top-10/" rel="noopener noreferrer"&gt;LLM01&lt;/a&gt;, MITRE ATLAS &lt;a href="https://atlas.mitre.org/" rel="noopener noreferrer"&gt;AML.T0054&lt;/a&gt;). Keep the model read-only and gate everything it returns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hallucinated fields reach your store.&lt;/strong&gt; A model may return a plausible &lt;code&gt;src_ip&lt;/code&gt; that was never in the line. Validate format and cross-check against the raw event before writing anything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-determinism defeats detection.&lt;/strong&gt; The same line can parse two ways on two runs. Anything feeding a detection rule needs a deterministic path or a validation gate, not a raw model output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost scales with volume.&lt;/strong&gt; Send representatives, not raw streams. If your token bill scales linearly with log volume, the architecture is wrong.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where to Learn This
&lt;/h2&gt;

&lt;p&gt;The hard part is not prompting. It is knowing which step is deterministic (templating, aggregation, format validation) and which is a language task (labeling clusters, explaining an anomaly, drafting a query), then wiring them so the model never sits where a wrong answer causes damage. Teams that get value here already understood their log schemas and detection logic; the model amplifies that engineering, it does not supply it.&lt;/p&gt;

&lt;p&gt;GTK Cyber's &lt;a href="https://dev.to/courses/applied-data-science-ai"&gt;Applied Data Science and AI for Cybersecurity&lt;/a&gt; course is built for security practitioners who want to connect these pieces on real data, with the judgment to keep the model where it helps. The &lt;a href="https://dev.to/blog/how-to-use-generative-ai-security-operations"&gt;generative AI in security operations post&lt;/a&gt; covers the same split for the broader SOC.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Apply Machine Learning to Threat Hunting</title>
      <dc:creator>Charles Givre</dc:creator>
      <pubDate>Fri, 10 Jul 2026 15:39:01 +0000</pubDate>
      <link>https://dev.to/cgivre/how-to-apply-machine-learning-to-threat-hunting-2li3</link>
      <guid>https://dev.to/cgivre/how-to-apply-machine-learning-to-threat-hunting-2li3</guid>
      <description>&lt;p&gt;Machine learning in threat hunting is oversold in one specific way: vendors imply the model finds the threat. It does not. A hunt still starts with a hypothesis and a human who knows the environment. What machine learning does well is one narrow, valuable job: it shrinks the candidate set. Instead of an analyst scrolling through 40,000 outbound sessions, ML hands them 40 that do not look like the rest.&lt;/p&gt;

&lt;p&gt;That reframing decides where ML belongs in a hunt and where it wastes your time. Here is how to apply it without pretending it replaces judgment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start With Whether You Have Labels
&lt;/h2&gt;

&lt;p&gt;The first decision is not which algorithm to use. It is whether you have labeled examples of the thing you are hunting.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You have labels.&lt;/strong&gt; For well-studied problems, curated datasets exist: DGA domains, phishing URLs, known malware families. Here supervised classification works. Extract features and train a classifier. See &lt;a href="https://dev.to/blog/detecting-dga-domains-python"&gt;detecting DGA domains in Python&lt;/a&gt; for a worked example using lexical features and a gradient-boosted model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You do not have labels.&lt;/strong&gt; This is most hunting. You are looking for something you cannot name yet, so there is nothing to train a classifier against. This is where unsupervised methods earn their place: clustering to group events, and distance-based scoring to rank them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are unsure which camp a hunt falls into, it is almost always the second one. For the difference in practice, see &lt;a href="https://dev.to/blog/supervised-vs-unsupervised-learning-security"&gt;supervised vs. unsupervised learning for security&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clustering to Collapse Candidate Sets
&lt;/h2&gt;

&lt;p&gt;The most useful unsupervised technique in hunting is not anomaly scoring. It is clustering, used to reduce volume. Group thousands of similar events into a handful of clusters, then hunt the small and the odd ones.&lt;/p&gt;

&lt;p&gt;Command-line execution (MITRE ATT&amp;amp;CK &lt;a href="https://attack.mitre.org/techniques/T1059/" rel="noopener noreferrer"&gt;T1059&lt;/a&gt;) is a good target. Sysmon Event ID 1 and Windows Event ID 4688 give you the full command line. Most command lines in an environment are near-duplicates of each other: the same scheduled tasks, the same management scripts, the same installer strings. The rare ones are what you want.&lt;/p&gt;

&lt;p&gt;Vectorize the command lines with a character n-gram TF-IDF, then let &lt;a href="https://scikit-learn.org/stable/modules/generated/sklearn.cluster.DBSCAN.html" rel="noopener noreferrer"&gt;&lt;code&gt;DBSCAN&lt;/code&gt;&lt;/a&gt; from &lt;a href="https://scikit-learn.org/" rel="noopener noreferrer"&gt;scikit-learn&lt;/a&gt; label the outliers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.feature_extraction.text&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TfidfVectorizer&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.cluster&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DBSCAN&lt;/span&gt;

&lt;span class="c1"&gt;# df: one row per process creation, with a 'command_line' column
&lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TfidfVectorizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;analyzer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;char_wb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ngram_range&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;min_df&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit_transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;command_line&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;fillna&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DBSCAN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;min_samples&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;metric&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cosine&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cluster&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;labels_&lt;/span&gt;

&lt;span class="c1"&gt;# cluster == -1 is DBSCAN's noise label: command lines that resemble
# nothing else in the dataset. Rare by construction, worth hunting.
&lt;/span&gt;&lt;span class="n"&gt;rare&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cluster&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;sort_values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;command_line&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;char_wb&lt;/code&gt; n-grams handle the obfuscation you see in real command lines: base64 blobs, mixed casing, inserted characters. A &lt;code&gt;PowerShell -enc&lt;/code&gt; payload will not cluster with anything legitimate and drops straight into the noise group. The same pattern works on outbound HTTP sessions, DNS query strings, and user-agent values. You are not asking the model "is this malicious." You are asking "is this like everything else," which is a question ML answers reliably.&lt;/p&gt;

&lt;h2&gt;
  
  
  Peer-Group Anomaly for Account Behavior
&lt;/h2&gt;

&lt;p&gt;Single-user baselining has a known failure mode: if an account is compromised early, or you only have a short history for it, its baseline is either poisoned or too thin to be useful. Peer-group comparison sidesteps this. Compare each account to the accounts most like it, not only to its own past.&lt;/p&gt;

&lt;p&gt;Build a feature vector per account (distinct hosts reached, off-hours logon ratio, privileged operations, distinct source IPs), group accounts by role or organizational unit, and measure how far each account sits from its peers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;

&lt;span class="c1"&gt;# features: DataFrame indexed by account, grouped by 'role'
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;peer_distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;numeric&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;centroid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;std&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numeric&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;centroid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;   &lt;span class="c1"&gt;# distance from peer centroid
&lt;/span&gt;
&lt;span class="n"&gt;features&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;peer_score&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;features&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;group_keys&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;peer_distance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;suspects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;features&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort_values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;peer_score&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ascending&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;head&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A service account that suddenly behaves like an interactive admin, or a helpdesk user reaching servers no one else in helpdesk touches, surfaces here even when their own history looks unremarkable. This is the useful core of what vendors sell as UEBA, and it maps cleanly to lateral movement (MITRE ATT&amp;amp;CK &lt;a href="https://attack.mitre.org/techniques/T1021/" rel="noopener noreferrer"&gt;T1021&lt;/a&gt;) and account manipulation hunts.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Work Is Feature Engineering, Not the Model
&lt;/h2&gt;

&lt;p&gt;Every example above spends more effort turning raw logs into features than on the algorithm. That is not incidental. The choice between &lt;code&gt;DBSCAN&lt;/code&gt; and &lt;code&gt;KMeans&lt;/code&gt;, or between a random forest and gradient boosting, rarely decides whether a hunt succeeds. The features do. A byte-ratio, an inter-arrival coefficient of variation, an entropy score on a domain string: these are what carry signal. Spend your time there. See &lt;a href="https://dev.to/blog/feature-engineering-security-machine-learning"&gt;feature engineering for security machine learning&lt;/a&gt; for the patterns that hold up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Machine Learning Stops
&lt;/h2&gt;

&lt;p&gt;Be honest about the limits, because the failures are predictable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It will not generate hypotheses.&lt;/strong&gt; ML ranks and groups what you point it at. Deciding to hunt command-line execution, or peer-group deviation, or beaconing, is your call. The model has no idea what an attacker looks like.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The base-rate problem is unforgiving.&lt;/strong&gt; Malicious activity is a tiny fraction of all activity, so a small false positive rate still buries the real findings. Use ML to prioritize, then filter with cheap rules (known-good ASNs, expected admins) before an analyst sees anything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It is blind to living-off-the-land.&lt;/strong&gt; If attackers use the same tools your admins use, statistically unusual is not the same as malicious. This is the same limit that constrains &lt;a href="https://dev.to/blog/anomaly-detection-security-operations"&gt;anomaly detection in security operations&lt;/a&gt;: map your MITRE ATT&amp;amp;CK threat model explicitly against what the model can and cannot see.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Findings need validation before they become detections.&lt;/strong&gt; A cluster or a high peer-score is a lead, not a verdict. Confirm it, then translate reliable logic into a production detection rather than rerunning a notebook forever.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Applied well, machine learning is a force multiplier for a hunter who already knows what questions to ask. GTK Cyber's applied data science training covers exactly this: building and calibrating these models against realistic security datasets, with hands-on labs on the feature engineering, clustering, and peer-group techniques described here.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>AI Security Training for Healthcare Security Teams</title>
      <dc:creator>Charles Givre</dc:creator>
      <pubDate>Wed, 08 Jul 2026 15:00:53 +0000</pubDate>
      <link>https://dev.to/cgivre/ai-security-training-for-healthcare-security-teams-15kp</link>
      <guid>https://dev.to/cgivre/ai-security-training-for-healthcare-security-teams-15kp</guid>
      <description>&lt;p&gt;Healthcare organizations are wiring LLMs and machine learning into clinical work: ambient documentation that drafts notes from a visit, chatbots that answer patient questions, retrieval over the EHR, and predictive models for sepsis, readmission, and imaging triage. Each of these is a new attack surface, and most healthcare security teams were trained for networks and endpoints, not models and training data.&lt;/p&gt;

&lt;p&gt;The skills gap is specific. Here is what healthcare cybersecurity professionals actually need to train on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping PHI Out of the Model Pipeline
&lt;/h2&gt;

&lt;p&gt;The first problem is data exposure, and it does not look like a normal data breach. Protected health information ends up in places a network review never checks: inside LLM prompts, in the retrieval context a &lt;a href="https://python.langchain.com/docs/tutorials/rag/" rel="noopener noreferrer"&gt;RAG&lt;/a&gt; pipeline pulls from the EHR, in application and model-provider logs, and in every call to an external inference API.&lt;/p&gt;

&lt;p&gt;HIPAA's Safe Harbor method requires removing 18 identifiers (names, geographic subdivisions, dates, medical record numbers, and more) before data counts as de-identified. Security teams need to know where PHI enters a pipeline and strip it before it does. &lt;a href="https://github.com/microsoft/presidio" rel="noopener noreferrer"&gt;Microsoft Presidio&lt;/a&gt; is a practical starting point for detecting and redacting identifiers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;presidio_analyzer&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AnalyzerEngine&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;presidio_anonymizer&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AnonymizerEngine&lt;/span&gt;

&lt;span class="n"&gt;analyzer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AnalyzerEngine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;anonymizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AnonymizerEngine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Patient John Doe, MRN 00219384, seen on 2026-06-14 for chest pain.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;analyzer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;analyze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entities&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PERSON&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DATE_TIME&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;language&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;clean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anonymizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;anonymize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;analyzer_results&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clean&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# -&amp;gt; "Patient &amp;lt;PERSON&amp;gt;, MRN 00219384, seen on &amp;lt;DATE_TIME&amp;gt; for chest pain."
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The lesson to teach alongside the tool: de-identification is imperfect. Named-entity recognition misses custom identifiers like that MRN unless you add a recognizer, and even Safe Harbor data carries re-identification risk. De-identify before data reaches the model, log what you send, and treat the model provider as a data flow, not a black box.&lt;/p&gt;

&lt;h2&gt;
  
  
  Red-Teaming Clinical LLM Features
&lt;/h2&gt;

&lt;p&gt;A patient-facing chatbot or a clinician copilot is an application that takes untrusted input and acts on it. That makes it a target for prompt injection. Direct injection overrides the system prompt through user input. Indirect injection hides instructions in a document the model retrieves, which matters most in healthcare because RAG pipelines routinely ingest clinical notes, uploaded records, and patient messages that an attacker can influence (OWASP &lt;a href="https://owasp.org/www-project-top-10-for-large-language-model-applications/" rel="noopener noreferrer"&gt;LLM01&lt;/a&gt;, MITRE ATLAS &lt;a href="https://atlas.mitre.org/techniques/AML.T0051" rel="noopener noreferrer"&gt;AML.T0051&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Security teams should train to test these features the way they test a web app: send adversarial input, try to override instructions, attempt to exfiltrate the system prompt or connected data, and write findings mapped to OWASP and ATLAS. We cover the mechanics in &lt;a href="https://dev.to/blog/red-teaming-llm-powered-applications"&gt;how to red team an LLM-powered application&lt;/a&gt; and &lt;a href="https://dev.to/blog/rag-poisoning-llm-jailbreaking"&gt;RAG poisoning and jailbreaking&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Diagnostic Models Under Attack
&lt;/h2&gt;

&lt;p&gt;The models that carry the highest stakes are the ones influencing clinical decisions. These can be fooled. Finlayson et al. showed in Science (2019) that small, human-imperceptible perturbations flip the output of dermatology and radiology classifiers. This is a model-evasion attack (MITRE ATLAS &lt;a href="https://atlas.mitre.org/techniques/AML.T0015" rel="noopener noreferrer"&gt;AML.T0015&lt;/a&gt;), and it applies to any ML model tied to a clinical or billing outcome.&lt;/p&gt;

&lt;p&gt;Vendor accuracy numbers are measured on clean data. Healthcare security teams need to evaluate robustness under adversarial pressure, not accept the marketing figure. The methodology is the same one we teach for any security-relevant model, covered in &lt;a href="https://dev.to/blog/evaluating-ml-model-robustness-security"&gt;how to evaluate ML model robustness for security use cases&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Constraints That Change the Threat Model
&lt;/h2&gt;

&lt;p&gt;The attack techniques are not healthcare-specific. The constraints are. PHI exposure is a regulatory event under HIPAA. Model evasion against a diagnostic tool is a patient-safety event. And the FDA governs AI/ML-based Software as a Medical Device, including how a deployed model can be updated, so change management on a model is not a purely internal decision. Training that ignores these stakes teaches the mechanics but misses the point.&lt;/p&gt;

&lt;p&gt;None of this requires a data science degree. Security practitioners already have the adversarial mindset; what they need is the AI-specific layer and time in a lab against real targets. GTK Cyber teaches that layer in hands-on courses like &lt;a href="https://dev.to/courses/ai-red-teaming"&gt;AI Red-Teaming&lt;/a&gt; and &lt;a href="https://dev.to/courses/applied-data-science-ai"&gt;Applied Data Science and AI&lt;/a&gt;, and delivers custom, on-site training for security teams that need it mapped to their own environment.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Integrate ChatGPT or Claude Into a SOC</title>
      <dc:creator>Charles Givre</dc:creator>
      <pubDate>Mon, 06 Jul 2026 15:27:55 +0000</pubDate>
      <link>https://dev.to/cgivre/how-to-integrate-chatgpt-or-claude-into-a-soc-5oc</link>
      <guid>https://dev.to/cgivre/how-to-integrate-chatgpt-or-claude-into-a-soc-5oc</guid>
      <description>&lt;p&gt;The useful question is not whether to put a large language model in your SOC. It is where the model plugs in. Answer that wrong and you either get a chatbot nobody uses or an agent with enough privilege to become your next incident. Answer it right and you remove real toil from tier-1 without adding a new attack surface.&lt;/p&gt;

&lt;p&gt;The short version: the model sits beside your SIEM and SOAR as an enrichment and drafting service, called from your existing pipeline, and it never sits in the critical decision path. This post is about the wiring. For the broader question of what generative AI is and is not good at in security work, see &lt;a href="https://dev.to/blog/how-to-use-generative-ai-security-operations"&gt;how to use generative AI in security operations&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Reference Architecture
&lt;/h2&gt;

&lt;p&gt;Do not point analysts at a chat window. Build an event-driven service:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your SIEM or SOAR fires a webhook when an alert crosses a threshold.&lt;/li&gt;
&lt;li&gt;An enrichment service you control assembles the fields the model needs (the alert, recent auth history, relevant threat intel), redacting what it should not see.&lt;/li&gt;
&lt;li&gt;The service calls the model API with a fixed output schema.&lt;/li&gt;
&lt;li&gt;It validates the response and writes a draft verdict, confidence, and rationale back to the case.&lt;/li&gt;
&lt;li&gt;A human still decides. State-changing actions stay with the human or with a deterministic SOAR playbook.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The model is a callout in your pipeline, no different in principle from a VirusTotal or GreyNoise lookup. It produces text; your systems remain the source of truth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the API, and Force Structured Output
&lt;/h2&gt;

&lt;p&gt;The consumer ChatGPT and Claude apps give you no retention control, no output contract, and no audit log. For anything touching production alerts, use the API: the OpenAI &lt;a href="https://platform.openai.com/docs/api-reference" rel="noopener noreferrer"&gt;Chat Completions or Responses API&lt;/a&gt; or the &lt;a href="https://docs.anthropic.com/en/api/messages" rel="noopener noreferrer"&gt;Anthropic Messages API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The important move is to stop parsing prose. Force the model to return a schema that drops straight into case management. On Anthropic, tool use doubles as a structured-output mechanism: define a tool, force the call, get validated JSON. OpenAI's structured outputs and function calling do the same.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;anthropic&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anthropic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Anthropic&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# reads ANTHROPIC_API_KEY
&lt;/span&gt;
&lt;span class="n"&gt;triage_tool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;record_triage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Record the triage verdict for a single security alert.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input_schema&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;properties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verdict&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;enum&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;benign&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;suspicious&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;malicious&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;number&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;minimum&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maximum&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mitre_techniques&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;array&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;items&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rationale&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;required&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verdict&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rationale&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-haiku-4-5-20251001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;# cheap model for high-volume queue work
&lt;/span&gt;    &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;triage_tool&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;tool_choice&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;record_triage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You are a SOC tier-1 triage assistant. Classify the alert using only the &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fields present in the input. Do not invent indicators not in the data.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;alert_json&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;verdict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_use&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;enum&lt;/code&gt; stops the model from inventing a new category. Log the &lt;code&gt;confidence&lt;/code&gt; and route anything low-confidence to a human instead of auto-closing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give the Model Tools With MCP, Read-Only First
&lt;/h2&gt;

&lt;p&gt;Static triage on a single alert is worth something. An investigation that pulls related context is worth more, and that means letting the model call your tools. The clean way to standardize this is the &lt;a href="https://modelcontextprotocol.io/" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt; (MCP), an open standard for exposing tools and data to models. Both the Anthropic API and a growing set of OpenAI clients speak it, so one MCP server serves multiple models.&lt;/p&gt;

&lt;p&gt;Start with read-only tools: &lt;code&gt;search_siem&lt;/code&gt;, &lt;code&gt;lookup_ip_reputation&lt;/code&gt;, &lt;code&gt;get_user_auth_history&lt;/code&gt;. A minimal MCP server that wraps a SIEM query looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp.server.fastmcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastMCP&lt;/span&gt;

&lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastMCP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;soc-tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@mcp.tool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_auth_history&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Return this user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s authentication events (read-only).&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;siem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;index=auth user=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; earliest=-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hours&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;h | fields _time, src_ip, action&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rule that keeps this safe: every input the model reads is potentially attacker-controlled. The body of a phishing email, a hostname in a log, a field in a retrieved document; an attacker who can write to any of those can attempt prompt injection. OWASP ranks prompt injection as LLM01 in its &lt;a href="https://genai.owasp.org/llm-top-10/" rel="noopener noreferrer"&gt;Top 10 for LLM Applications&lt;/a&gt;, and MITRE ATLAS tracks it as &lt;a href="https://atlas.mitre.org/" rel="noopener noreferrer"&gt;AML.T0054&lt;/a&gt;. Constrain the agent the way you constrain a service account:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read-only by default.&lt;/strong&gt; Query, enrich, and summarize tools are safe to grant. &lt;code&gt;isolate_host&lt;/code&gt; and &lt;code&gt;disable_user&lt;/code&gt; require human confirmation or a deterministic playbook, never an unattended model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Least privilege per tool.&lt;/strong&gt; The auth-history tool does not need write access to anything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bound the blast radius.&lt;/strong&gt; Rate-limit tool calls, cap agent turns, and log every invocation as a privileged action.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Route by Severity to Control Cost
&lt;/h2&gt;

&lt;p&gt;A SOC processing tens of thousands of alerts a day cannot send all of them to a frontier model. Route by severity. Tier-1 queue triage goes to a fast, cheap model like Claude Haiku 4.5 (&lt;code&gt;claude-haiku-4-5-20251001&lt;/code&gt;). Escalations that a human already cares about (correlating artifacts, drafting an incident timeline) go to Sonnet 5 (&lt;code&gt;claude-sonnet-5&lt;/code&gt;) or Opus 4.8 (&lt;code&gt;claude-opus-4-8&lt;/code&gt;), or the OpenAI equivalent. Cheap model for volume, capable model for the cases that earn it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep Sensitive Data Out of the Call
&lt;/h2&gt;

&lt;p&gt;The integration is only as safe as its data handling. Send the model the fields the task needs, not raw logs carrying credentials, PII, or full payloads. Redact or hash identifiers before the API call. Use an enterprise tier with a zero-retention, no-training agreement and keep that contract for your auditors. For regulated data, run retrieval locally with &lt;a href="https://github.com/pgvector/pgvector" rel="noopener noreferrer"&gt;pgvector&lt;/a&gt; and a self-hosted embedding model and pass only the snippet, or deploy the model inside your own tenant via Amazon Bedrock or Google Vertex. The pattern is the same discipline you already enforce on every other third-party callout.&lt;/p&gt;

&lt;h2&gt;
  
  
  Roll Out in Shadow Mode
&lt;/h2&gt;

&lt;p&gt;Do not flip this on live. Run it in shadow mode first: the model produces a verdict, a human still decides, and you compare. Track two numbers, agreement rate against your analysts and cost per alert. Promote a task from shadow to assisted only when the agreement rate earns it, and keep a human on every irreversible action indefinitely.&lt;/p&gt;

&lt;p&gt;The teams that get value from wiring ChatGPT or Claude into a SOC are the ones who already understood their detection logic and data flows. The model amplifies the pipeline you have; it does not replace the engineering. GTK Cyber's &lt;a href="https://dev.to/courses/applied-data-science-ai"&gt;Applied Data Science and AI for Cybersecurity&lt;/a&gt; course is built for exactly that: security practitioners who want to connect LLMs to real workflows, with the judgment to know where the model belongs and where it does not.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
