- Critical Thinking - Bug Bounty Podcast
- Posts
- [HackerNotes Ep. 115] Mentee to Career Hacker - So Sakaguchi
[HackerNotes Ep. 115] Mentee to Career Hacker - So Sakaguchi
Justin and So Sakaguchi sit down to walk through some recent bugs, before having a live mentorship session. They also talk about Reflector, and finish up by doing a bonus podcast segment in Japanese!
Hacker TL;DR
XSS in Excalidraw: What inspired @Mokusou4 to look for this bug was that he noticed Excalidraw had some XSS issues, after reading reports by @spaceraccoonsec and @elmehdimee. (report1, report2)
Looking at the source code, he found string concatenations when importing SVGs from external hosts. Since Excalidraw is a whiteboard where you can't just type in XSS, he had to find other ways the app interacts with uploaded content.
He discovered by uploading a malicious file & adding it to Excalidraw library, the XSS would trigger whenever someone opened that library. Cool bug!
“A Google Bug”: The second one was a collab between So and Justin. They found a widely used Google component that creates iframes. Due to its flexibility across Google products, origin checks were tricky, letting them access postMessage handlers.
After reviewing the component and found they could send postMessages to the iframe, which then made HTTP requests to Google's API. The successful responses came back with an Auth header, being a perfect gadget as it was automatically added.
Two requests were being sent - first with a
?domain=
parameter for origin checking, and second for the actual API call. With some fuzzing, they found that sometimes both 'domain=google.com' and 'domain=attacker.com' would get through.Using CSPT they could hit any API endpoint. The final piece came when Justin found they could use
$httpHeaders
in Google's RPC interface to set thecontent-type
toapplication/x-protobuf
.The chain:
Used
$httpHeaders
for the rightcontent-type
Hit any RPC endpoint via CSPT
Bypassed domain checks
Controlled the request body
Got sensitive data in the response
Live Mentorship: In the live mentorship segment, Justin shares his mentoring approach and tips. Here's what he focuses on when working with mentees:
Understanding their bug bounty career goals
Pentester vs Bug Bounty Hunter comparison:
Pentesters get a stable salary but might work on less interesting projects
Bug hunters have freedom but face income uncertainty
Pro-tip for aspiring full-time bug hunters:
Save up and pay yourself a monthly salary from your business account
This gives you the freedom to explore new research areas without financial pressure
Even Justin admits the pressure to find bugs never goes away - you have to actively remind yourself to relax!
Bring a Bug(3): Justin shared an XSS bug that he found together with So. The XSS worked in a completely unexpected way.
They discovered that
<base>
tag was automatically generated in the page's innerHTML. This tag is used to specify the base URL and target for relative URLs, and they realised they could potentially redirect to a location they controlled.When values were inserted into the <base> tag's href attribute, a forward slash would be prepended and it would be treated as a PATH. For example, something like
url.tld/path/injected-value
. They tried//
and backslashes and double quotes, but nothing worked. So as a last resort, they decided to try using HTML Entities!Normally you would use HTML special characters in the format
&#(HEX);
, but since the#
would break the path, they used HTML Entity names instead. For example,<
is written as<
. Using this method with the<base>
tag, they were able to load their payload from a location they controlled

ThreatLocker Cloud Control leverages built-in intelligence to assess whether a connection from a protected device originates from a trusted network.
By analyzing connection patterns from protected computers and mobile devices, it automatically identifies and allows trusted connections.
Find out more here:
Bring a Bug!
— XSS in Excalidraw:
First of all, what inspired @Mokusou4 to go look for this bug was that he noticed Excalidraw had a bit of a problem with XSS, after reading this report by @spaceraccoonsec and this other one by @elmehdimee.
So he started looking at the source code and app behaviour, and he stumbled upon some string concatenations when importing some .svg
files from an external host into the .Excalidraw format. His approach consisted of finding ways the app interacts with the stuff that gets thrown in there, because as you may know, Excalidraw is basically a whiteboard so there is no way to get an XSS by typing things in there, you have to look around and find interesting interactions.
What he found was that if he uploaded a malicious file, it wouldn’t trigger the XSS right away, but if he uploaded and stored it in an Excalidraw library, the XSS would trigger whenever a user opened the library containing the malicious file. Cool bug!
— “A Google Bug”
The second one was a collab between So and Justin. It started with Justin finding an interesting component that was used everywhere in Google products - it creates an iframe, and this component needs to be very flexible because of all the ways it needs to be used across Google products.
Because the component needed to function across multiple products, the origin checks were flexible. This flexibility allowed them to manipulate the component and gain access to its postMessage
handlers, which in turn enabled them to send postMessage
communications.
They had to study how each component worked and understand thoroughly how the application handled the data sent by the user, which led them to find a very restrictive way to send postMessages to that iframe which subsequently got sent as an HTTP request to Google API.
One of the good things was that if the request was successful, the response was sent back via postMessage. Luckily, the Authorization header was added by default and could determine a successful request by the response.
Summarising the first attack vector: they could include the Auth header in the response for a request that was being sent to the iframe → Google API.
After some time, they figured out that there were actually 2 requests that were being sent. The first was adding the origin as a ?domain=
parameter, and the second one was the one they had the response for. So it looked like the first request was being used as a kind of an origin check, which kinda makes sense when you think that this component had to be very flexible and reachable from a lot of places.
In the postMessage they could send, it was possible to add parameters, so the first thing So thought of was adding something like domain=google.com#
to potentially override a parameter and truncate the path. However, that didn't work as the end of the request was overridden back to the right domain. Dead end, right? Not really, So fired up Intruder and after sending some requests he noticed that once in a while they got a response containing both domain=google.com
and domain=attacker.com
.
For whatever reason, all they had to do was send a bunch of requests that eventually one of them went through. That’s a win, but they’re not there yet!
Since the request was a POST, they had to figure out a way to hit different API endpoints, and they achieved that via a CSPT. By manipulating a segment of the path they had control over, they were able to inject ../../../
to navigate back to the root, allowing them to send anything to any endpoint. That part done, they now had to deal with the POST method. They discovered the X-HTTP-Method-Override:
header, but since they didn’t have a way to manipulate the headers, it wasn’t much use. I decided to include it here anyway since it was new to me, so it might be new to you too.
Almost all Google APIs can be reached in multiple ways, and one of them is via the RPC interface. They fiddled with that for a bit but couldn’t make it work due to a content-type conflict. The key realization came when Justin discovered that some Google APIs using RPC allow you to specify arbitrary HTTP headers via $httpHeaders
. That meant they could explicitly set the required Content-Type
to application/x-protobuf
, allowing them to interact with the RPC-based paths/methods.
Putting the chain together:
Used
$httpHeaders
to set the correctcontent-type
application/x-protobuf
)Hit the RPC endpoint with a POST request using CSPT to reach any endpoint
Bypassed the domain check with that bug that triggered for unknown reasons
Had full control of the request body
Sent the request in the proto schema
Received the response with sensitive data, extracted stuff, etc.
What a chain!
Live Mentorship Session
In the live mentorship part of the pod, Justin and So discuss how Justin's mentorship works and the things he usually does for his mentees. Let's go through the stuff he cares about so we can all feel a little bit mentored by him too. We won't discuss So's answers because they are personal to him, but I'll add some good points from their discussion here.
What the mentee wants to do with their BB career
The good and bad of being a Pentester vs. Bug Bounty Hunter:
As a Pentester you have a fixed salary, you have stability but sometimes you have to deal with some applications and companies you don’t want to work with or things you’re not interested.
As a Bug Bounty Hunter you get to be directly paid for your efforts and results, which is good but sometimes you get paid nothing for quite some time. You can work on stuff you’re excited about and have 100% freedom to do whatever you want to do.
A good tip from Justin for the people who are starting to consider going full time as a bug bounty hunter:
Build some bank and start paying yourself a fixed amount every month from your business account instead of relying on bounty earnings directly. One day you'll realize you have enough money to pay yourself for quite some time, and you can use that time to do something you want. For example, you can do some research you're not sure will pay out, or study some vulnerability types you're interested in but didn't want to deviate from your bread and butter vulns because you thought you needed the money.
And if you don't like this approach and think that you have to keep finding more and more vulns, Justin said that this kind of anxiety never goes away. Even he, knowing that he has enough money to pay himself a generous amount for quite some time, constantly finds himself under pressure and has to make a conscious effort to think "I'm fine, chill".
Reflector is a Caido plugin you can use from inside the EvenBetter plugin to check for reflected XSS. It takes parameters and performs checks that may lead you to find XSS. The thing is, it wasn't always finding stuff and was giving too many false negatives, so Justin and So sat down and spent an entire week improving it.
They made it analyse cookies and improved the reflection check. Now it also analyses sanitisation as well. Because sometimes some characters get encoded while others don't, it now accounts for that when analysing the output of all the checks it makes.
It might be worth checking out if you’re a Caido user!
日本語でハッキングの事を話す時間だ!
いつもは英語でポッドキャストを収録しているんですけど、ジャスティンの願いが叶って今回は途中から日本語に切り替えることになりました!COホストとして参加した私も、そこからは日本語でお喋りを続けることに!
いつものように、ポッドキャストに参加する人は必ずバグを紹介しないといけないんですが、今回はジャスティンの番で、しかも日本語で発表することになりました!笑笑
バグを見せて!
ジャスティンは坂口さんと一緒に見つけたバグを紹介してくれました。このバグは最終的にXSSになったんですが、面白いことに、予想もしなかった方法でXSSが成立したんです!
ページのinnerHtmlで<base>タグが勝手に作られるのを見つけて、ちょっと変だなと思ったんです。この<base>タグって、ドキュメント内の相対URLのベースURLやターゲットを指定するものなんですけど、こんな動きをするなんて面白いですよね。そこで、もしかしたらこれを使って、自分たちがコントロールできる場所に何かをリダイレクトできるんじゃないかなって.
この<base>タグの中身は<href>に入れられていたんですけど、面白いことに、指定した値の前にスラッシュ(/)が付いちゃうんです。だから、完全なURLじゃなくて、PATHとして扱われちゃうんですよね。hrefに値を入れられるんだけど、その値が既存のURLの二番目のパスに入っちゃうんだよね。例えば、url.tld/path/注入値 みたいな感じで。「//」でやってみようと思ったんだけど、全然うまくいかなかったんです。バックスラッシュ使ってみたり、ダブルクォーテーションも使ってみたんだけど、どれもダメでした。そこで、最後の手段としてHTML Entitiesを使うことにしたんです!
ジャスティンはいつも、数字の場合は「&#(HEX);」
形式のHTML特殊文字を使ってたんだけど、HEXの代わりに名前を使うこともできるんだよね。例えば、「<」
は 「<
」って書き方なんですけど、「#」を使うとパスが途切れちゃうから、HTML Entityの名前を使う方がいいかなって思った。そこで、HTML Entities使って、その<base>タグで、自分たちがコントロールできるところからpayloadを取ってこれるようになったんです!
Hacking Culture in Japan
Enough with writing in Japanese! Even though they kept speaking Japanese, I don't want to do this to you (haha). Hopefully, I wrote it well enough so you can use a translator to convert it to whatever language you prefer.
Justin asked So about the hacking culture in Japan, including the community and bug bounty platforms. Let's add a bit of that conversation here too so you can learn about Japan's hacking culture as well.
In general, the hacking culture here is pretty weak. There are no big platforms like HackerOne and Intigriti, and even though there are a few groups on LINE and Facebook, they're not as active as one might expect. In the few platforms that exist here, most programs are VDP so So doesn't care much about those. Even Japanese companies, when they are serious about security, tend to post their programs on bigger platforms like HackerOne.
When hacking, Justin mentioned that it's really difficult to understand what's going on when looking at Japanese websites. He asked So if it's easier for him to hack Japanese websites because it's his native language, and what he thinks about hacking websites in a foreign language. Surprisingly, So answered that he changes the language of the sites he's hacking to English whenever he can, because Japanese characters often break things since they are Unicode blocks, making it a pain to figure out what's going on. This issue isn't present in languages that use standard ASCII characters.
Also, reading documentation in English is a lot easier because code is in English, and tech in general uses English as its primary language, so reading anything that isn't English makes it harder to understand. (and I agree)
So also mentioned that English being a must is probably one of the reasons why the bug bounty culture isn’t very strong in Japan, but CTFs are quite popular here for some unknown reason, maybe because it’s more like a game? Who knows. Justin lived here a few years and he knows how difficult it is to find someone who speaks English without struggling too much.
Maybe one of the reasons why CTFs are popular in Japan is because CTFs have an almost clear path for you to follow. Usually, there aren't many rabbit holes, so even though you might spend 15 hours getting a flag, you feel like you've learned a lot in the process. With bug bounty, on the other hand, you have an infinite amount of things going on at the same time and the path isn't clear, so maybe it's a cultural thing, but people in Japan tend not to find it as interesting.
Back to the hacking in English vs. Japanese topic, here’s something funny that you may not know about Japan’s design philosophy: they keep the UI really busy, with a hell lot of stuff on the screen so everything is “easy” to reach. Design is really simple and functional, but if you’re not used to how websites look in Japan I bet you’ll feel lost.
Here’s how https://www.yahoo.co.jp looks like compared to the one you’re used to.

Well, that's it! Hopefully, you found this week's HackerNotes interesting. I apologize if I made any mistakes while writing in Japanese. I'm not used to writing in Japanese, so it was a fun exercise for me too.
If you want to check So’s podcast (it’s in Japanese ofc), you’ll find the links below:
いつも通り、keep hacking!