Understanding Code Property Graphs

When I first started developing tools for source code auditing, my primary need was to track tainted data flows through complex codebases during manual code reviews. Initially, I turned to Tree-Sitter, which proved excellent for single-file analysis with its fast, incremental parsing capabilities. However, as I scaled to larger codebases with complex cross-file dependencies and data flows, Tree-Sitter’s AST-only approach became limiting. The challenge wasn’t just parsing individual files. It was understanding how data flows between functions, across modules, and through various execution paths during thorough manual security assessments.

[Read More]

Code auditing 101

Topics covered

This post explores the evolution from manual code review to automated security testing, covering:

  • The reality of manual code review and its limitations
  • Understanding vulnerabilities vs weaknesses
  • How SAST tools work under the hood
  • Taint analysis and data flow tracking
  • Sink-to-source vs source-to-sink methodologies
  • Mitigation strategies: whitelisting vs blacklisting
  • Dealing with false positives in practice
  • Choosing and implementing SAST tools at scale
  • The complementary relationship between manual and automated testing

It’s 3 AM. You’re on your fifth cup of coffee, eyes bloodshot, staring at line 2,847 of a 10,000-line pull request. Somewhere in this maze of curly braces and semicolons lurks a SQL injection vulnerability that could bring down your entire application. Welcome to the glamorous world of manual code review!

[Read More]

Amazon AppSec CTF: HalCrypto

Executive Summary

  • Challenge: HalCrypto
  • Category: Web Security
  • Vulnerability: JWT validation bypass via URL confusion with @ symbol
  • Impact: Authentication bypass leading to admin access
  • Flag: HTB{r3d1r3c73d_70_my_s3cr37s}

Vulnerability Overview

Attack Flow Diagram

Attack Flow Diagram

Source-to-Sink Analysis

1. Entry Point - JWT Authentication (Source)

The vulnerability starts when the AuthMiddleware processes JWT tokens:

// middleware/AuthMiddleware.js:5-34
module.exports = async (req, res, next) => {
    try {
        if (req.cookies.session === undefined) {
            if (!req.is('application/json')) return res.redirect('/');
            return res.status(401).send(response('Authentication required!'));
        }
        return JWTHelper.getHeader(req.cookies.session)
            .then(header => {
                if (header.jku && header.kid) {
                    // VULNERABILITY: Weak URL validation using lastIndexOf
                    if (header.jku.lastIndexOf(config.AUTH_PROVIDER, 0) !== 0) {
                        return res.status(500).send(response('The JWKS endpoint is not from localhost!'));
                    }
                    return JWTHelper.getPublicKey(header.jku, header.kid)
                        .then(pubkey => {
                            return JWTHelper.verify(req.cookies.session, pubkey)
                                .then(data => {
                                    req.user = data.user;
                                    return next();
                                })
                                .catch(() => res.status(403).send(response('Authentication token could not be verified!')));
                        })
                        .catch(() => res.redirect('/logout'));
                }
                return res.status(500).send(response('Missing required claims in JWT!'));
            })
            .catch(err => res.status(500).send(response("Invalid session token supplied!")));
    } catch (e) {
        return res.status(500).send(response(e.toString()));
    }
}

2. The Vulnerable Validation - String-based URL Check

The critical vulnerability lies in line 14 of AuthMiddleware.js:

[Read More]

Amazon AppSec CTF: PageOneHTML

Executive Summary

  • Challenge: PageOneHTML
  • Category: Web Security
  • Vulnerability: Server-Side Request Forgery (SSRF) via gopher:// protocol
  • Impact: Access to internal API endpoint leading to flag disclosure
  • Flags:
    • Local: HTB{f4k3_fl4g_f0r_t3st1ng}
    • Remote: HTB{l1bcurL_pla7h0r4_0f_pr0tocOl5}

Source-to-Sink Analysis

1. Entry Point - User Input (Source)

The vulnerability starts at /api/convert endpoint which accepts user-controlled markdown content:

// routes/index.js:15-28
router.post('/api/convert', async (req, res) => {
    const { markdown_content, port_images } = req.body;  // User input

    if (markdown_content) {
        html = MDHelper.makeHtml(markdown_content);      // Convert MD to HTML
        if (port_images) {                               // If port_images is true
            return ImageConverter.PortImages(html)       // Process images
                .then(newHTML => res.json({ content: newHTML }))
                .catch(() => res.json({ content: html }));
        }
        return res.json({ content: html });
    }
    return res.status(403).send(response('Missing parameters!'));
});

2. Image Processing - Protocol Confusion

The ImageConverter extracts all <img> tags and processes their src attributes:

[Read More]