Five years shipping React and Next.js on AWS. Now I secure the systems I used to build. I ship llm-audit, an OWASP LLM Top 10 scanner on npm. From commercial construction in Spain to application security in Charleston, SC.
GIAC GSEC + GFACT · GCIH + AWS Security Specialty in progress · US Work Authorized
Static analysis for TypeScript and JavaScript LLM applications. OWASP LLM Top 10 at commit time. It catches the security failure modes AI coding assistants quietly introduce, in the TS/JS ecosystem Semgrep's official AI pack does not cover.
install
shell
npm i -D llm-audit
npx llm-audit demo # all 5 rules vs bundled vulnerable fixtures
What it catches
LLM01: Prompt Injection
User-controlled input flowing into the LLM `system` role across Anthropic, OpenAI, and the Vercel AI SDK.
vulnerable
import { generateText } from "ai";
export async function vuln(req: any) {
return generateText({
model: "claude-opus-4-7" as any,
system: req.body.persona, // user controls the system prompt
prompt: "Tell me about portfolios.",
});
}
LLM02: Insecure Output Handling
Model output piped into `eval`, `dangerouslySetInnerHTML`, `child_process.exec`, or raw `innerHTML`.
vulnerable
import { generateText } from "ai";
export async function VulnComponent() {
const r = await generateText({
model: "claude-opus-4-7" as any,
prompt: "give me html",
});
return <div dangerouslySetInnerHTML={{ __html: r.text }} />;
}
LLM02: Insecure Output Handling
`JSON.parse` on raw model output without a schema validator on the path.
vulnerable
import { generateText } from "ai";
export async function vuln() {
const r = await generateText({
model: "claude-opus-4-7" as any,
prompt: "respond with JSON: { user, balance }",
});
return JSON.parse(r.text); // shape is whatever the model emits
}
These days, most of my work mixes web development with LLM features. Right now I'm running a prompt-injection lab against a chatbot I built, testing how well the usual defenses hold up under realistic attack patterns. Findings live at /ai-playground. That work fed into llm-audit, an OWASP LLM Top 10 static analyzer I ship on npm for TypeScript and JavaScript codebases.
By day I'm at GDNA, building cloud-native apps on AWS. The interesting parts sit on the boundary between feature development and security: input validation, auth flows, S3 policies, secrets handling, and figuring out where things break when no one's watching.
My security path started with the SANS Cyber Academy scholarship, which got me the GIAC GFACT and GSEC certifications. GIAC GCIH (SEC504), PortSwigger BSCP, and TCM's web pentest cert (PWPA) are in progress. AWS Security Specialty is on the roadmap for later in 2026.
Before software: I'm from Spain, six years in commercial construction (structural detailing, CAD, project management). Studied architectural engineering at IE University.
Analyzed 173K VPC flow records across 579 log files: isolated 33,232 attacker flows from 20.106.124.93, determined a 6.5-hour attack window, quantified 265MB exfiltrated on port 8889 and 190MB on port 80, and confirmed the full attack surface (HTTP, SSH, 8889) using PCAP-to-NetFlow conversion with nfpcapd/nfdump.
Investigated a 628K-packet PCAP in Wireshark: used protocol hierarchy and conversation statistics to surface a port-80 scanning pattern from 3.142.238.241, followed an HTTP stream revealing a successful WordPress brute-force login (Hydra, admin/#AlphaInc!), and completed a live-capture exercise extracting an HTTP object from loopback traffic.
WiresharkPCAP analysisDisplay filtersHTTP stream following
Analyzed PCAP traffic with tcpdump: identified /.env probing, WordPress brute-force with Hydra, and cleartext login parameters visible in the HTTP payload.
Lab 4.3 - Intrusion Detection and Network Security Monitoring with Snort3 and Zeek
Validated Snort 3.1.73 config, tightened HOME_NET to 10.130.0.0/16, ran the community ruleset against investigate.pcap, and surfaced an SSH CRC32 overflow shellcode pattern (294 alerts from 20.106.124.93 → 10.130.8.94:22). Re-ran Snort with a BPF filter pinned to the attacker IP, then processed the same PCAP with Zeek's extract-all-files policy and confirmed log output.
Lab 2.1 - Network Discovery and Service Enumeration with Nmap
Ran the Nmap recon funnel across 172.30.0.0/24: a privileged ARP ping sweep (sudo nmap -sn) found a host (172.30.0.26) that the unprivileged sweep missed, then full TCP connect scans (-sT -p 1-65535) and version detection (-sV) mapped the services. Findings included Dropbear SSH 2022.83 hiding on non-standard port 2430 plus nginx and MariaDB on 172.30.0.20, an exposed MongoDB 5.0.27 on 172.30.0.26 that the mongodb-databases NSE script enumerated without authentication (config, local, admin, builds), and an SMB/NetBIOS server (FILESTOR) on 172.30.0.114 whose smb2-security-mode reported message signing enabled but not required. Saved the MongoDB scan with -oN for reporting.
Ran Nmap against a /24 lab network: identified 7 live hosts, enumerated services (OpenSSH, MySQL, nginx, php-fpm), attempted OS fingerprinting, baselined results to XML, and used ndiff to catch a newly exposed Python WSGI server on port 8000. Confirmed the finding by SSHing in and reviewing netstat, iptables, and the served page.
First engineering role after JRS Coding School bootcamp. Promoted from Software Engineer I to II. Full-stack development on Angular/NestJs stack with Azure cloud services.
Key Achievements:
Built custom Chrome extensions integrated with CRM tools using RESTful APIs and OAuth 2.0
Developed and maintained full-stack features using Angular, NestJs, MongoDB, and Azure Cosmos DB
Created Azure Functions with various triggers, reducing infrastructure costs for client workloads
Mentored junior developers and coordinated between development and leadership teams
llm-audit: Static Analysis for TypeScript LLM Apps (2026)
Role: Solo build: rules, CLI, fixtures, distribution, docs, self-audit. v1 plan adds 7 more rules.
OWASP LLM Top 10 at commit time. A Semgrep rule pack and npm CLI for catching the security failure modes AI coding assistants quietly introduce in TS/JS LLM applications. Live on npm.
Problem
AI coding assistants reproduce a small, predictable set of security failures in LLM-integrated code: untrusted input flowing into the LLM `system` role, model output piped into `eval` or `dangerouslySetInnerHTML`, hardcoded API keys, JSON.parse on raw model output. Existing OSS SAST tooling (Semgrep `p/ai-best-practices`, agent-audit) is Python-only. The TypeScript and JavaScript ecosystem (Vercel AI SDK, Next.js Server Actions, OpenAI / Anthropic JS SDKs) was uncovered.
Approach
Built a focused Semgrep rule pack mapped explicitly to OWASP LLM Top 10, distributed via npm with a thin CLI that wires up a husky pre-commit hook and a GitHub Action workflow. Five rules in v0, each with vulnerable + safe fixtures, exercised by a test runner. Released under MIT.
Outcome
Live on npm at version 0.0.2 with a self-audit and full documentation. Caught a real LLM02 (Insecure Output Handling) bug in this very portfolio's recruiter-fit endpoint and shipped the fix in the same session.
SemgrepTypeScriptNode.jsOWASP LLM Top 10npmGitHub Actions
Reproducible red-team study of prompt-injection techniques mapped to OWASP LLM Top 10 and MITRE ATLAS, tested across frontier and budget-tier models via Vercel AI Gateway. Week 1 of 4 in flight; matrix UI, filters, transcripts, and a live sandbox land in weeks 2-4.
Problem
Production LLM features ship with informal defenses. Whether they hold up under structured attack chains is mostly anecdote, with no published, reproducible matrix of attack vs. model vs. mitigation in the open TS/JS ecosystem.
Approach
Catalog prompt-injection techniques mapped to OWASP LLM Top 10 and MITRE ATLAS. Run each attack across frontier and budget-tier models via Vercel AI Gateway. Pin model IDs and commit prompts to source so every result is reproducible. Each attack ships paired with a defensive mitigation.
Outcome
Week 1 scaffold live at /ai-playground with seeded attacks across multiple OWASP categories. Weeks 2-4 add the matrix UI, filters, slide-over transcripts, and a live sandbox.
OWASP LLM Top 10MITRE ATLASVercel AI GatewayNext.jsTypeScript
Mentorship platform onboarding ~1,200 users. Built React UI components and the authentication flow with security-focused defaults.
Problem
Mentorship platform needed secure, scalable onboarding for ~1,200 users.
Solution
React UI components and a Cognito-backed authentication flow with session handling and security headers. Input validation across 4 form types covering ~40 questions. Infrastructure provisioned with scoped IAM access controls.
Impact
60% improvement in onboarding efficiency. Secure registration and sign-in live in production.