I have spent 18 years building software across SaaS, fintech and payments, much of it in regulated, audited and security-sensitive environments. Today most of my open-source time goes into PandaWard, a local application security assessment engine that keeps evidence for every finding and says plainly what it did not test. Alongside it I build payment infrastructure at Payshen, maintain tooling for payment developers and review payment, webhook and auth code in other projects.
| Venture | Role and focus |
|---|---|
| Payshen | Founder and Managing Director. Payment orchestration: every provider through one integration, each payment routed to the provider most likely to approve it, retried elsewhere only when that is safe, with the reason recorded. |
| AMIO | Founder and Managing Director. Buy now, pay later: connects shoppers, merchants and financing partners so paying in instalments is simple and the terms are clear from the start. |
| afend | Founder. Guided ISO/IEC 27001:2022 readiness, from risk register to an auditor-ready handoff. |
Work in other projects that their maintainers merged or changed because of it.
| Project | What happened |
|---|---|
| Adyen | Reported that the Node HMAC validator accepted a malformed key as an empty one (#1816). Adyen confirmed it and asked for fixes across its SDKs: merged in Node, Java and .NET; PHP, Python, Go and Ruby in review. |
| Svix | Two PHP webhook fixes merged: empty or non-base64 secrets are rejected (#2765) and Webhook::fromRaw works again (#2768). |
| Go | Reported that oauth2.DeviceAccessToken panics when a server returns a negative or very large polling interval (golang/go#82658); fixed in golang.org/x/oauth2 (CL 855541). |
| Google Gen AI SDK | Review of go-genai #1024: on Vertex AI the access token would still have followed a redirect to another domain, because the auth transport signs every hop again; the author adopted the fix in the PR. |
| Twilio | Review of HMAC-SHA256 webhook support in twilio-node (#1226): the Express middleware still checked SHA-1 only; Twilio fixed it in the PR and merged it. |
| Razorpay | Review of razorpay-node #492: network errors would have carried the API key secret into application logs; fixed in the PR with tests. |
| PayPal | Review of paypal-js #1100 on v6 script reuse across namespaces; adopted in the PR. |
| Standard Webhooks | Review of binary payload signing (#348); merged with the memoryview fix the review asked for. |
| Model Context Protocol | Review of the Go SDK client credentials flow (#1451); merged after revision. |
Application security assessment for your own repositories that also tells you what it did not test. Most scanners print alerts and stop; PandaWard keeps a ledger of every control it could check, how it checked it and the redacted evidence, and lists every control it could not decide. Passive by default, network tests only after a person approves the scope. Formerly PenSec, renamed in 0.2.0.
- Honest coverage: only PASS and FAIL are decisive; blocked, unsupported or suspected controls never count as secure.
- Evidence, not opinions: each finding links to a redacted, SHA-256 addressed evidence record and is fingerprinted across runs, so a fix counts only when the check runs again.
- No AI-confirmed findings: review agents can only record hypotheses, and the engine reads and redacts the cited lines itself.
- Wide static coverage: secrets, injection sinks, CI/CD, containers, Terraform, Android and iOS manifests, webhooks, MCP and LLM output reaching exec sinks.
- Reports and CI: HTML, Markdown, JSON, SARIF 2.1.0 and CSV, with a
--fail-ongate. Release binaries are reproducible, with checksums, an SBOM and signed provenance.
/plugin marketplace add ratomirjovanovic/pandaward
/plugin install pandaward@pandaward # macOS and Linux
/plugin install pandaward-windows@pandaward # Windows
/pandaward:scan
Live demo · Website · Docs · Quick start · Releases · Roadmap
Paste an API response, webhook or postback and see what the provider reported, what the code means, which events belong together and what looks wrong. Nothing leaves the browser.
- Deterministic analysis: structural provider detection, documented error catalogs, correlation by explicit identifiers and explainable diagnostic rules.
- Wide coverage: card processors, wallets, pay-by-bank, crypto and high-risk billing providers, each with an honest capability manifest.
- Privacy by design: sensitive data redacted from everything shown or exported, identifiers masked, strict Content Security Policy, no server-side processing.
- Three ways to run it: a static demo, an offline CLI and a Next.js app with a passkey-protected admin area.
Live demo · Demo video (1 min) · Docs · Releases · Roadmap · Good first issues
Official client libraries for the Payshen payment orchestration API: payments, captures, voids, refunds, events and webhook verification. Published and maintained on four registries.
Node.js on npm · Python on PyPI · PHP on Packagist · WooCommerce on WordPress.org
Recent public reviews, mostly payment, webhook and security changes. The last column shows what GitHub recorded after the review: whether the author pushed changes, whether I approved, and whether the pull request was merged.
23 pull requests in 18 projects · 15 revised by their authors after the review · 9 merged
| Project | Pull request reviewed | Since the review |
|---|---|---|
| razorpay/razorpay-node | #492 Preserve network errors when the API does not respond | Revised, then approved |
| medusajs/medusa | #17489 fix(payment): recompute refunded amount when a refund fails at the provider | Merged after revision |
| mark3labs/mcp-go | #1123 fix(oauth): refresh an access token shortly before it expires | Revised, then approved |
| googleapis/go-genai | #1024 fix: strip the API key from a redirect to another domain | Revised, then approved |
| better-auth/better-auth | #12049 fix(account): share and guard concurrent provider token refreshes | Revised after review |
| svix/svix-webhooks | #2732 fix(php,ruby): fallback to case-insensitive header lookup in webhook verify | Revised after review |
| twilio/twilio-node | #1226 chore: support HMAC-SHA256 webhook signatures in validateRequest | Merged after revision |
| better-auth/better-auth | #12014 fix(stripe): refetch subscription in subscription webhooks | Closed |
| DataDog/dd-trace-js | #10932 fix(appsec): wrap shared Stripe webhooks methods only once | Closed |
| paypal/paypal-js | #1100 fix(paypal-js): only reuse a pending v6 script for the same namespace | Revised after review |
| standard-webhooks/standard-webhooks | #348 Sign binary payloads byte for byte (JavaScript, Python) | Merged after revision |
| modelcontextprotocol/go-sdk | #1451 auth/extauth: send resource in client credentials token requests | Merged after revision |
Problems I found while integrating or reviewing other projects, reported upstream.
| Project | Issue | Status |
|---|---|---|
| modelcontextprotocol/rust-sdk | #1442 auth: tokens that live 30s or less are refreshed on every request | Open |
| golang/go | #82658 x/oauth2: DeviceAccessToken panics on a negative or very large interval | Fixed |
| go-pay/gopay | #558 Is there a private way to report a security issue? | Open |
| Adyen/adyen-node-api-library | #1816 [Bug]: HmacValidator accepts a malformed HMAC key as an empty key | Fixed |
| cashfree/cashfree-pg-sdk-nodejs | #133 PGVerifyWebhookSignature never checks x-webhook-timestamp, so an old webhook... | Open |
| payloadcms/payload | #19055 plugin-ecommerce: restore the Stripe cart drift check with a metadata digest,... | Open |
| getlago/lago | #842 [BUG]: No private way to report a security issue on GitHub | Open |
| svix/svix-webhooks | #2763 php: Webhook accepts an empty or non-base64 secret and verifies with an empty... | Fixed |
| medusajs/medusa | #17544 [Bug]: Payment providers removed from config are never disabled in payment_pr... | Fixed |
| supabase/ssr | #209 tsconfig.json: outDir without rootDir triggers TS6059 / migration warning whe... | Fixed |
Fixes I wrote for other projects that their maintainers merged.
| Project | Pull request | Merged |
|---|---|---|
| Adyen/adyen-node-api-library | #1817 fix(hmac): reject malformed HMAC keys and compare signatures exactly | 2026-11-03 |
| Adyen/adyen-dotnet-api-library | #1899 fix(hmac): reject an empty HMAC key | 2026-11-03 |
| Adyen/adyen-java-api-library | #2100 fix(hmac): don't include the HMAC key in the invalid key exception | 2026-11-03 |
| svix/svix-webhooks | #2768 php: fix Webhook::fromRaw | 2026-10-30 |
| svix/svix-webhooks | #2765 php: reject an empty or non-base64 webhook secret | 2026-10-29 |
The Adyen fixes follow #1816, an HMAC validation issue I reported and Adyen confirmed. Related fixes for the PHP, Python, Go and Ruby libraries are in review.
This card and the review list above are generated daily from public GitHub data. My contribution activity is GitHub's own overview, below this README.
| Area | Focus |
|---|---|
| Payments and fintech | PSP integrations, orchestration and routing, decline and error semantics, webhooks, settlement and reconciliation |
| Application security | Static analysis and evidence-based assessment, secrets handling, CI/CD and supply chain, webhook and auth review |
| GRC | ISO/IEC 27001 readiness, risk and supplier management, control evidence, secure design |
| Engineering | TypeScript, Go and Python services, API clients and SDKs, testing and CI, documentation that matches the code |
| Area | Tools |
|---|---|
| Languages | |
| Frameworks | |
| Data and cloud | |
| Delivery |




