Sponsored Advertisement
Back to Blog
Originally published on Medium.Read Original Article
2026-05-09
ailarge-language-modelslm-studiosoftware-developmentai-agent

Building an Autonomous Security Auditor with LangGraph and LM Studio

In the world of cloud security, speed is everything. A misconfigured port can lead to a breach in minutes. While traditional scanners alert ...

Building an Autonomous Security Auditor with LangGraph and LM Studio

In the world of cloud security, speed is everything. A misconfigured port can lead to a breach in minutes. While traditional scanners alert you, an Agentic Workflow can scan, reason, and remediate the issue without human intervention.

The Architecture: A Circular Logic

Traditional code runs in a straight line. Agents run in a loop: Think → Act → Observe. LangGraph is the perfect framework for this because it allows us to define this loop as a state machine.

Part 1: The Tools (The Agent’s Hands)

An LLM by itself is just a brain in a jar; it cannot “do” anything. Tools give the agent the ability to interact with the world.

@tool
def list_vulnerable_instances():
    """Returns instances with security vulnerabilities."""
    # ... logic to scan cloud ...
    return mock_instances

@tool
def stop_instance(instance_id: str):
    """Issues a STOP command to remediate a vulnerable instance."""
    return f"REMEDIATED: Instance {instance_id} stopped."
  • Why it’s needed: The @tool decorator creates a schema that the LLM reads. It tells the LLM: "Here is a function you can call, and here is exactly what it does."
  • The Logic: list_vulnerable_instances acts as the "eyes," and stop_ibm_instance acts as the "hands."

Part 2: The Agentic Brain (Reasoning)

This is where we connect to our local LLM (running on LM Studio) and provide it with a “personality” and a “mission.”

# Connecting to local LM Studio
llm = ChatOpenAI(base_url="http://localhost:1234/v1", api_key="lm-studio", model="google/gemma-4-e4b")
llm_with_tools = llm.bind_tools(tools)
  • LM Studio Integration: By setting the base_url to localhost:1234, we keep our data private. No security logs ever leave your local machine.
  • System Message: We define the agent’s constraints. We explicitly tell it to scan first, then remediate, then summarize. This prevents the agent from “guessing” what to do.

This post will walk you through building an autonomous Security Remediation Agent using LangGraph and a local LLM via LM Studio. We will break down the code to understand how to move from “Chat AI” to “Action AI.”

Building an Autonomous Security Auditor with LangGraph and LM Studio

In the world of cloud security, speed is everything. A misconfigured port can lead to a breach in minutes. While traditional scanners alert you, an Agentic Workflow can scan, reason, and remediate the issue without human intervention.

The Architecture: A Circular Logic

Traditional code runs in a straight line. Agents run in a loop: Think → Act → Observe. LangGraph is the perfect framework for this because it allows us to define this loop as a state machine.

Part 1: The Tools (The Agent’s Hands)

An LLM by itself is just a brain in a jar; it cannot “do” anything. Tools give the agent the ability to interact with the world.

Python

@tool
def list_vulnerable_instances():
    """Returns instances with security vulnerabilities."""
    # ... logic to scan cloud ...
    return mock_instances

@tool
def stop_instance(instance_id: str):
    """Issues a STOP command to remediate a vulnerable instance."""
    return f"REMEDIATED: Instance {instance_id} stopped."
  • Why it’s needed: The @tool decorator creates a schema that the LLM reads. It tells the LLM: "Here is a function you can call, and here is exactly what it does."
  • The Logic: list_vulnerable_instances acts as the "eyes," and stop_ibm_instance acts as the "hands."

Part 2: The Agentic Brain (Reasoning)

This is where we connect to our local LLM (running on LM Studio) and provide it with a “personality” and a “mission.”

Python

# Connecting to local LM Studio
llm = ChatOpenAI(base_url="http://localhost:1234/v1", api_key="lm-studio", model="google/gemma-4-e4b")
llm_with_tools = llm.bind_tools(tools)
  • LM Studio Integration: By setting the base_url to localhost:1234, we keep our data private. No security logs ever leave your local machine.
  • System Message: We define the agent’s constraints. We explicitly tell it to scan first, then remediate, then summarize. This prevents the agent from “guessing” what to do.

Part 3: The Workflow Graph (The Nervous System)

This is the “secret sauce” of LangGraph. We define nodes (tasks) and edges (the paths between tasks).

workflow = StateGraph(State)
workflow.add_node("agent", agent)
workflow.add_node("tools", ToolNode(tools))
workflow.add_node("notify", slack_notifier)

workflow.add_edge(START, "agent")
workflow.add_conditional_edges("agent", route)
workflow.add_edge("tools", "agent") # The Loop
workflow.add_edge("notify", END)
  • The Circular Edge: Notice workflow.add_edge("tools", "agent"). This is what makes it an agent. After the agent stops a server, it goes back to the "agent" node to verify if there are more servers left to fix.
  • The Conditional Route: The route function is the decision-maker. It checks the LLM's response: "Did the AI ask to use a tool? If yes, go to 'tools'. If no, the job is done—go to 'notify'."

Part 4: Scheduling & Governance

We don’t want this to run just once. Security is a continuous process.

def run_scheduled_audit():
    while True:
        app.invoke({"messages": [HumanMessage(content="Start the audit.")]})
        time.sleep(AUDIT_INTERVAL_SECONDS)
  • Continuous Monitoring: This loop ensures the agent wakes up every 5 minutes, checks the environment, and puts itself back to sleep.
  • Slack Notifier: Every time an audit finishes, the slack_notifier node sends a summary of the remediation actions, providing a perfect audit trail for human administrators.

Part 5: Decoding the Agent’s “Internal Monologue” (The Logs)

To truly understand how an autonomous agent differs from a script, we have to look at the execution logs. In the world of LangGraph, logs aren’t just errors; they are a play-by-play of the agent’s reasoning process.The

**Audit Execution Trace **Here is the actual output from our security remediation run:

2026-05-11 09:46:45,861 - INFO - Starting Audit #1
2026-05-11 09:46:49,651 - INFO - [agent] → AGENT: Requesting tools: list_vulnerable_instances
2026-05-11 09:46:49,652 - INFO - [route] → ROUTE: Executing 1 tool(s)
2026-05-11 09:46:49,655 - INFO - [list_vulnerable_instances] Starting security audit.
...
2026-05-11 09:46:59,004 - INFO - [agent] → AGENT: Requesting tools: stop_instance
2026-05-11 09:47:13,180 - INFO - [agent] → AGENT: No tools requested, generating final response
2026-05-11 09:47:13,180 - INFO - [route] → ROUTE: Sending notification and ending workflow
2026-05-11 09:47:13,584 - INFO - [run_scheduled_audit] === Audit #1 Complete ===

What is happening under the hood?

  • The Intent Phase: At 09:46:49, the LLM recognizes the goal and decides it cannot proceed without data. It explicitly calls list_vulnerable_instances. This is the Think phase.
  • The Execution Phase: The route logic detects this tool call and directs the workflow to the tools node. At 09:46:49,655, our Python function executes. This is the Act phase.
  • The Remediation Loop: After getting the list, the agent doesn’t stop. It evaluates the list and realizes it must call stop_instance. It does this iteratively until the list is clear.
  • The Termination Condition: At 09:47:13, the LLM looks at the history and decides, "I have found the issues, I have stopped the instances, and I have nothing left to do." It stops requesting tools, triggering the route to move to the notify node.

Full code: https://github.com/imdurgadas/security-remediation-agent

Clap, share, comment, and provide your thoughts. Please share your opinions with me! Please follow to receive notifications on new articles.

Image

Sponsored Advertisement