Probing Postman Passwords with Playwright and Postdigger

Adversis sampled over 8,000 API collections from over 2,000 teams from Postman and found that around 40% or 853 users had some kind of API token or password exposed.

Probing Postman Passwords with Playwright and Postdigger

We're back with some more data spelunking!

When tasked with an adversary emulation exercise against an organization writing its own apps, don't overlook the treasure trove of credentials and infrastructure details outlined in the API development platform Postman.

To be clear, Postman isn't doing anything wrong here, and they've even made it easier for users to protect their secrets. But as with any potential area for risk, it's helpful to highlight the issue for awareness.

Uncovering the API authentication details isn't straightforward; one must painstakingly sift through requests. So we turned to the browser testing software Playwright, transforming a mind-numbing manual task into an efficient automated process.

Identifying Unique Postman Accounts

Leveraging GAU (Get All URLs), we queried URLs across various platforms, honing in on unique Postman accounts. This helped us identify almost 100,000 unique accounts.

% echo postman.com | gau > accounts.txt
% wc -l accounts.txt
98346 accounts.txt

With those in hand, we started spelunking.

Unleashing the Power of Playwright

Playwright is a library designed to automate browsers with a unified API, which proved highly potent in our exploration. JavaScript frameworks make web scraping a bit more challenging, but Playwright helps make this trivial, albeit not as easily scalable. Installation is as simple as:

pip install --upgrade pip
pip install playwright
playwright install

You can then launch a browser and navigate as shown below:

from playwright.sync_api import sync_playwright
with sync_playwright() as playwright:
    browser = playwright.chromium.launch(
        headless=False,
    )
    context = browser.new_context(
        user_agent=UA
    )
    context.set_default_timeout(TIMEOUT)
    page = context.new_page()

    page.goto("https://adversis.io/")

    page.wait_for_load_state("domcontentloaded")
    time.sleep(1)

Though Playwright has a slight learning curve, it's incredibly versatile. Refer to the debug section and the test generator docs; it might save you from doing things the hard way when built-in methods exist.

Secrets, Secrets Everywhere

To infinity - of my sandbox. Buzz lightyear toy of the neighbor boy.
Photo by Veit Hammer / Unsplash

The prevalence of exposed tokens and passwords, even within development and QA environments, is not to be taken lightly.

We sampled over 8,000 API collections from over 2,000 teams and found that around 40% or 853 users had some API token or password exposed.

Over 1,000 unique passwords were retrieved, and over 2,000 JWTs were exposed. Of the JWTs, dozens were still valid (and a few were long-lived - 46 years to be exact) and contained 128 email addresses, many of them corporate.

Spot checks of the credentials revealed valid API tokens at a major HR vendor, an Atlassian Jira Cloud tenant, and a corporate Microsoft Azure account. As expected, most appeared to be development and QA environments.

Unfortunately, we've been in far too many environments where production data made its way to QA, or the QA environment had just a few too many connections back into prod.

As a recon method, searching through requests can also identify subdomains, test domains, and other infrastructure that may be overlooked.

Who's affected?

A tiny sample like this leaves out virtually everyone. Still, from the small window we investigated, we found some interesting names, including major insurance carriers, telecom companies, major SaaS companies, consulting firms, CPA companies, and many individuals.

Look for your company name or domain and ensure there aren't valid secrets or tokens exposed!

Training and Verification

Photo by Alex Radelich / Unsplash

This highlights the need for secure developer training and regular audits of your external security posture. And Postman's recent introduction of secret variable types and masking is commendable. For comprehensive guidance, refer to OWASP's Secrets Management Cheat Sheet and Postman's Blogs.

Notable principles outlined in those resources include:

  • Not embedding API keys directly in code.
  • Storing API keys as variables in Postman.
  • Keeping tokens private within teams.
  • Using placeholders for API key values.
  • Storing API keys in environment variables outside the source tree.
  • Restricting API key usage, deleting unnecessary keys, and rotating them periodically.

Conclusion

This exercise in data spelunking shines yet another light on the dangers of exposed credentials in commonly used tools and platforms. Secure development is a continuous challenge, demanding continuous vigilance, awareness, and strong practices.

Hard coding keys and passwords are the easy path. Still, Postman's guidelines offer a good solution for securing API keys and tokens — a journey that all organizations must embark on, especially if you're working with corporate credentials.

Postdigger: The code is on Github, and is basic Python leveraging Playwright, showcasing the impressive power of GUI automation. It's worth noting that this approach is brittle and may not survive basic UI updates to Postman. YMMV.