🥇 #1: Replace HTTP GET with Correct Verbs on State-Changing Endpoints
Impact: High
Effort: Low
Category: Security
PrismController.Remove (line 39 of Beam.Server/Controllers/PrismController.cs) is decorated [HttpGet] but performs a database DELETE. Any link, browser prefetch, log scanner, or
tag that resolves api/Prism/Remove/{UserId}/{RayId} will silently delete prisms with no user intent — a classic CSRF-by-GET vulnerability. UserController.Get compounds this: it auto-creates a new user account on every GET for an unknown username, so any web crawler or security scanner that touches api/User/Get/{anything} silently pollutes the users table with garbage accounts.
Implementation guidance
PrismController.cs — change Remove to [HttpDelete] and update the client:
// Before
[HttpGet("[action]/{UserId}/{RayId}")]
public List Remove(int UserId, int RayId)
// After
[HttpDelete("[action]/{UserId}/{RayId}")]
public List Remove(int UserId, int RayId)
BeamApiService.cs — use DeleteAsync instead of GetFromJsonAsync:
internal async Task<List> UnPrismRay(int rayId, int userId)
{
var resp = await http.DeleteAsync($"api/Prism/Remove/{userId}/{rayId}");
resp.EnsureSuccessStatusCode();
return (await resp.Content.ReadFromJsonAsync<List>()) ?? new List();
}
UserController.cs — separate lookup (GET) from creation (POST):
[HttpGet("[action]/{Username}")]
public IActionResult Get(string Username)
{
var existing = _context.Users.FirstOrDefault(u => u.Username == Username);
if (existing == null) return NotFound();
return Ok(existing.ToShared());
}
[HttpPost("[action]")]
public User GetOrCreate([FromBody] string Username)
{
var existing = _context.Users.FirstOrDefault(u => u.Username == Username);
if (existing != null) return existing.ToShared();
var newUser = new Data.User { Username = Username };
_context.Add(newUser);
_context.SaveChanges();
return newUser.ToShared();
}
Update BeamApiService.GetOrCreateUser to POST to the new endpoint. No migration is needed.
🥇 #1: Replace HTTP GET with Correct Verbs on State-Changing Endpoints
Impact: High
Effort: Low
Category: Security
PrismController.Remove (line 39 of Beam.Server/Controllers/PrismController.cs) is decorated [HttpGet] but performs a database DELETE. Any link, browser prefetch, log scanner, or
tag that resolves api/Prism/Remove/{UserId}/{RayId} will silently delete prisms with no user intent — a classic CSRF-by-GET vulnerability. UserController.Get compounds this: it auto-creates a new user account on every GET for an unknown username, so any web crawler or security scanner that touches api/User/Get/{anything} silently pollutes the users table with garbage accounts.
Implementation guidance
PrismController.cs — change Remove to [HttpDelete] and update the client:
// Before
[HttpGet("[action]/{UserId}/{RayId}")]
public List Remove(int UserId, int RayId)
// After
[HttpDelete("[action]/{UserId}/{RayId}")]
public List Remove(int UserId, int RayId)
BeamApiService.cs — use DeleteAsync instead of GetFromJsonAsync:
internal async Task<List> UnPrismRay(int rayId, int userId)
{
var resp = await http.DeleteAsync($"api/Prism/Remove/{userId}/{rayId}");
resp.EnsureSuccessStatusCode();
return (await resp.Content.ReadFromJsonAsync<List>()) ?? new List();
}
UserController.cs — separate lookup (GET) from creation (POST):
[HttpGet("[action]/{Username}")]
public IActionResult Get(string Username)
{
var existing = _context.Users.FirstOrDefault(u => u.Username == Username);
if (existing == null) return NotFound();
return Ok(existing.ToShared());
}
[HttpPost("[action]")]
public User GetOrCreate([FromBody] string Username)
{
var existing = _context.Users.FirstOrDefault(u => u.Username == Username);
if (existing != null) return existing.ToShared();
var newUser = new Data.User { Username = Username };
_context.Add(newUser);
_context.SaveChanges();
return newUser.ToShared();
}
Update BeamApiService.GetOrCreateUser to POST to the new endpoint. No migration is needed.