Skills on Tessl: a developer-grade package manager for agent skillsLearn more
Logo
Back to articlesDouble your coding agent’s chances of writing secure code with the CodeGuard Skill

12 Feb 202610 minute read

Simon Maple

Simon Maple is Tessl’s Founding Developer Advocate, a Java Champion, and former DevRel leader at Snyk, ZeroTurnaround, and IBM.

LinkedIn profile picture

John Groetzinger

Principal Engineer working on Generative AI and network security at Cisco.

AI coding agents are transforming how we write software. They autocomplete functions, generate boilerplate, and can scaffold entire features in seconds. But there's an uncomfortable truth we need to talk about: these models learned to code by reading the internet's code, including all of our bad security habits.


Every SQL injection vulnerability ever committed to a public repo? The model saw it. Hardcoded API keys in example code? Learned that too. Weak password hashing, missing input validation, insecure session management? It's all in the training data, and it will be replicated unless we take steps to prevent it.

So what can we do about it?


Teaching Your AI Agent to Write Secure Code

The solution isn't to stop using AI coding tools. They're far too valuable for that. Instead, we need to enable our AI agents with security knowledge that is automatically applied every time code is generated or reviewed.

This is where Agent Skills come in. Skills are reusable packages of instructions, rules, and context that enhance what an AI coding agent knows and how it behaves. Think of them as specialized training modules you can plug into your agent.

In this post, we’ll specifically be looking at the CodeGuard skill, which is built on Project CodeGuard, an open-source collection of security rules maintained by the great folks at Cisco, whom I was fortunate enough to present with at Cisco Live in Amsterdam recently on this very topic! While there, Cisco announced that it is donating the Code Guard project to the Coalition for Secure AI, which is a great move for the community.

  • 23 security rule categories spanning input validation, cryptography, authentication, session management, and more
  • Language-specific guidance for JavaScript, TypeScript, Python, Java, Go, Ruby, PHP, and many others
  • Always-apply rules that check every code operation (like never hardcoding credentials)
  • Context-specific rules that activate based on what you're building
image1

When this skill is loaded, your AI coding agent activates and applies these security rules, whether it's generating new code, reviewing existing code, or analyzing a pull request. From the eval shown above, we can see the skill gives 79% improvement on our real-world security scenarios compared to just using Claude Code alone.

Getting Started

Setting up the software-security skill takes about a minute:

1. Install the Tessl CLI:

npm install -g @tessl/cli

2. Install the security skill from your project directory:

tessl i cisco/software-security

That's it! The skill is now available to your AI coding agent, and the security rules are automatically loaded and applied.

Use Case 1: Writing Secure Code from Scratch

Let's see the skill in action. Imagine you ask your AI agent:

Write me a user login endpoint in Node.js with Express

Without security guidance

Coding agents are non-deterministic, so if you ask it to build this endpoint, it may one-shot a perfectly secure application. There’s also a good chance that without the security context to guide it, you will also see code like this:

const express = require('express');
const session = require('express-session');
const app = express();

app.use(session({
  secret: 'keyboard cat',
  name: 'connect.sid',
  cookie: { path: '/' }
}));

const users = [
  { name: 'admin', password: 'admin123' },
  { name: 'user', password: 'password' }
];

app.post('/login', (req, res) => {
  const { username, password } = req.body;

  const user = users.find(u =>
    u.name === username && u.password === password
  );

  if (user) {
    req.session.loggedIn = true;
    req.session.user = username;
    res.redirect('/dashboard');
  } else {
    res.status(401).send('Invalid credentials');
  }
});

This code works, but it's riddled with security issues, including direct password comparison without hashing, missing cookie flags, such as secure, httpOnly, or sameSite, making it potentially vulnerable to XSS and CSRF.

Using the Code Guard security skill

When the cisco/software-security skill is active, the agent knows to apply rules like codeguard-1-hardcoded-credentials and codeguard-0-session-management-and-cookies. The same prompt produces the following code:

const express = require('express');
const session = require('express-session');
const bcrypt = require('bcrypt');
const app = express();

// Session secret from environment variable 
app.use(session({
  secret: process.env.SESSION_SECRET,
  name: 'sessionId',  // Generic name, doesn't reveal framework
  cookie: {
    path: '/',
    secure: true,       // HTTPS only
    httpOnly: true,     // No JavaScript access
    sameSite: 'strict', // CSRF protection
    maxAge: 900000      // 15 minute timeout
  },
  resave: false,
  saveUninitialized: false
}));

app.post('/login', async (req, res) => {
  const { username, password } = req.body;

  // Validate input types to prevent NoSQL injection
  if (typeof username !== 'string' || typeof password !== 'string') {
    return res.status(400).send('Invalid input');
  }

  // Fetch user from database (credentials not in code)
  const user = await User.findOne({ username });

  if (!user) {
    // Constant-time response to prevent user enumeration
    await bcrypt.compare(password, '$2b$12$invalid.hash.for.timing');
    return res.status(401).send('Invalid credentials');
  }

  // Secure password comparison with bcrypt
  const valid = await bcrypt.compare(password, user.passwordHash);

  if (valid) {
    // Regenerate session to prevent session fixation
    req.session.regenerate((err) => {
      if (err) return res.status(500).send('Session error');

      req.session.loggedIn = true;
      req.session.userId = user.id;
      res.redirect('/dashboard');
    });
  } else {
    res.status(401).send('Invalid credentials');
  }
});

Use Case 2: Scanning an Existing Codebase

Writing secure code is one thing, but what about the millions of lines already deployed? The software-security skill is also capable of auditing existing codebases.

Let's examine a real-world example: nodejs-goof, an intentionally vulnerable application used for security training. This Node.js todo app contains the kind of vulnerabilities that exist in production codebases everywhere.

When we ask Claude Code to perform a security review with the skill active, it systematically scans the codebase and maps findings to specific CodeGuard rules.

image3

Finding 1: Hardcoded Secrets

File:app.js, lines 43 and 83

// Line 43 - Hardcoded session secret
app.use(session({
  secret: 'keyboard cat',
  name: 'connect.sid',
  cookie: { path: '/' }
}));

// Line 83 - Hardcoded API token
var token = 'SECRET_TOKEN_f8ed84e8f41e4146403dd4a6bbcea5e418d23a9';
console.log('token: ' + token);

Rule violated: codeguard-1-hardcoded-credentials.

The agent flags both issues and notes that the token is also being logged to the console, a double violation that could expose secrets in log aggregation systems.

Finding 2: Command Injection

File:routes/index.js, lines 155-166

var item = req.body.content;
var imgRegex = /\!\[alt text\]\((http.*)\s\".*/;
if (typeof (item) == 'string' && item.match(imgRegex)) {
  var url = item.match(imgRegex)[1];

  exec('identify ' + url, function (err, stdout, stderr) {
    // ...
  });
}

Rule violated: codeguard-0-input-validation-injection

This is a critical vulnerability. User input extracted from a regex match is concatenated directly into a shell command. An attacker could submit:

![alt text](http://example.com; rm -rf / "title)

This executes identify http://example.com; rm -rf / which will run some arbitrary command execution on the server.

The agent recommends using execFile with an arguments array instead of exec with string concatenation, and applying strict URL validation:

const { execFile } = require('child_process');
const validator = require('validator');

if (validator.isURL(url, { protocols: ['http', 'https'], require_protocol: true })) {
  execFile('identify', [url], { timeout: 5000 }, (err, stdout, stderr) => {
    // Safe: arguments are not interpreted by shell
  });
}

I’ll stop there, but it’s important to mention that each finding is mapped to a specific CodeGuard rule, making it easy to understand why something is a problem and how to fix it.

Use Case 3: Security Review of Pull Requests

A third way to use the software-security skill is at PR time. Before code reaches your main branch, you can have your AI agent review the diff for security issues.

The workflow looks like this:

  1. Developer opens a PR with new feature code
  2. Trigger a security review, either manually or via CI integration
  3. Agent analyzes the changed files, using applicable CodeGuard rules
  4. Issues are reported with severity, rule references, and remediation guidance

Here’s an example output from a Claude bot that was triggered on a PR, reviewing the code changes with the Code Guard skill.

image2

This catches vulnerabilities before they're merged, when they're cheapest to fix.

What's Inside the Skill?

The software-security skill is structured around the CodeGuard rules from Cisco's Project CodeGuard. Here's how it's organized:

Always-Apply Rules

These rules are checked on every code operation, regardless of language or context:

  • codeguard-1-hardcoded-credentials: Never hardcode secrets, passwords, API keys, or tokens
  • codeguard-1-crypto-algorithms: Use only modern, secure cryptographic algorithms
  • codeguard-1-digital-certificates: Validate and manage certificates securely

Language-Specific Rules

Rules are mapped to programming languages. For example, when you're writing JavaScript, you get rules applicable for (possibly not exclusive to) that language:

  • Input validation and injection prevention
  • Client-side web security (XSS, CSP)
  • Session management and cookies
  • API and web service security
  • Prototype pollution prevention
  • Supply chain security

Python gets rules for Django/Flask security, Java gets rules for Spring and JDBC, and so on.

Rule Categories

The full rule set covers various security domains:

CategoryWhat It Covers
Input Validation & InjectionSQL, NoSQL, LDAP, OS command, template injection
Authentication & MFAPassword policies, multi-factor, credential storage
Session ManagementCookie security, session fixation, timeout handling
CryptographyAlgorithm selection, key management, random number generation
API SecurityRate limiting, authentication, input validation
File HandlingUpload validation, path traversal, zip slip
DevOps & ContainersDocker security, CI/CD hardening
Cloud & KubernetesIAM, secrets management, network policies

Security as a First-Class Citizen

AI-generated code is here to stay. The productivity gains are too significant to ignore. But we can't let that productivity come at the cost of security.

By equipping your AI coding agent with the right skills, you get the best of both worlds: fast code generation with security best practices baked in.

The cisco/software-security skill brings Cisco's CodeGuard rules directly into your AI workflow. Whether you're writing new code, reviewing existing code, or validating pull requests don’t break production!

Discover more skills on the Tessl Registry, covering security best practices to API design guidelines and much more.

You can also build your own skills and share them with the community. If your team has internal security standards, publish a skill in your own workspace and ensure every coding agent in your org follows your policies and ways of working.

Join Our Newsletter

Be the first to hear about events, news and product updates from AI Native Dev.