[{"data":1,"prerenderedAt":2752},["ShallowReactive",2],{"blog-agentic-ai-work-flow-in-cybersecurity":3},{"post":4,"upNext":2719,"linkedPosts":2751},{"id":5,"title":6,"author":7,"body":8,"date":2702,"description":2703,"draft":2704,"extension":2705,"faq":2706,"image":2707,"lang":2708,"lastReviewed":2706,"link":14,"meta":2709,"navigation":192,"path":2710,"seo":2711,"stem":2712,"tags":2713,"type":2717,"__hash__":2718},"content\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity.md","Agentic AI Workflow ในงาน Cybersecurity","Tanuphat Chainaloedwong",{"type":9,"value":10,"toc":2699},"minimark",[11,16,33,36,41,44,49,52,68,71,74,88,91,94,105,108,2288,2298,2301,2309,2312,2315,2318,2325,2328,2335,2342,2349,2352,2363,2367,2370,2377,2380,2385,2393,2400,2403,2410,2413,2420,2425,2428,2434,2437,2444,2451,2457,2460,2467,2470,2477,2481,2484,2491,2495,2498,2505,2508,2515,2518,2525,2528,2535,2538,2544,2547,2554,2558,2561,2573,2576,2583,2586,2593,2599,2606,2612,2615,2622,2628,2631,2634,2641,2644,2651,2658,2665,2672,2676,2679,2683,2686,2689,2692,2695],[12,13,15],"h2",{"id":14},"agentic-ai-work-flow-in-cybersecurity","Agentic AI Work Flow In Cybersecurity",[17,18,19,20,27,28,32],"p",{},"ในปี 2025 เด็ก Generation Alpha เติบโตมาพร้อมกับเทคโนโลยีที่คาดว่าจะเปลี่ยนแปลงวิธีการทำงานในหลายภาคส่วนอย่างก้าวกระโดด นั่นคือ AI (",[21,22,23],"strong",{},[24,25,26],"em",{},"artificial intelligence",") โดยเฉพาะ gen-AI (Generative ",[21,29,30],{},[24,31,26],{},") และ Agentic AI ที่สามารถทำงานร่วมกัน แบ่งหน้าที่ และตรวจสอบข้อมูลกันเองได้ เพียงแค่ได้ยินแนวคิด (concept) นี้ก็รู้สึกว่ามันเจ๋งมากแล้ว แต่ถ้าเราฝันว่าจะให้ AI ทำงานแทนเราทั้งหมด ก็คงเหมือนวิชาแยกเงาพันร่างนั่นแหละ 555",[17,34,35],{},"ในบทความนี้เราจะมาพูดถึงการใช้งาน Agentic AI ในงาน cyber security กันนะครับ (จะลองไปด้วยกันเพราะผมเองก็ไม่เคยลองเหมือนกัน 555) โดยไม่ได้เน้นสอน dev หรือ cyber security แต่จะแชร์ไอเดียกันมากกว่า",[17,37,38],{},[21,39,40],{},"Agentic AI คืออะไร",[17,42,43],{},"Agentic AI คือระบบ AI ที่สามารถทำงานได้อย่างอิสระและมีเป้าหมายชัดเจน โดยมีความสามารถในการวางแผน ตัดสินใจ และดำเนินการเพื่อบรรลุเป้าหมายที่กำหนดไว้ ต่างจาก AI ทั่วไปที่มักจะตอบสนองต่อคำสั่งแบบตรงไปตรงมา Agentic AI จะสามารถทำงานร่วมกับ AI ตัวอื่นๆ แบ่งงานกันทำ และปรับเปลี่ยนแผนการทำงานได้ตามสถานการณ์",[45,46,48],"h4",{"id":47},"scope-of-task","Scope of Task",[17,50,51],{},"ก่อนที่เราจะไปทำ agent เรามาดูก่อนว่าจะให้มันช่วยงานอะไรเราได้บ้าง โดยยกตัวอย่างงานที่คิดว่าทำได้",[53,54,55,59,62,65],"ul",{},[56,57,58],"li",{},"ช่วยเก็บ information",[56,60,61],{},"ช่วยวิเคราะห์ attack surface ที่คาดว่าจะโดนโจมตี",[56,63,64],{},"automate exploit",[56,66,67],{},"เขียน report ?",[17,69,70],{},"จากงานที่เราเลือกมาข้างต้น ที่ง่ายที่สุดคงเป็นการช่วยเก็บ information เป้าหมาย",[17,72,73],{},"ต่อมาเราต้องแยกประเภท information ที่อยากจะเก็บก่อน (ยกตัวอย่าง web application)",[53,75,76,79,82,85],{},[56,77,78],{},"URL and Path",[56,80,81],{},"Service Port และ Version",[56,83,84],{},"HTTP Security header",[56,86,87],{},"Java Library และ Version",[45,89,78],{"id":90},"url-and-path",[17,92,93],{},"ในกระบวนการเก็บรวบรวม URL และ Path ต่างๆ ในเว็บไซต์ เราจำเป็นต้องใช้เทคนิคการทำ web crawling และ directory brute force",[95,96,101],"pre",{"className":97,"code":99,"language":100},[98],"language-text","Web crawling คือกระบวนการอัตโนมัติในการค้นหาและรวบรวมข้อมูลจากเว็บไซต์\nโดยระบบจะเข้าไปสำรวจและเก็บข้อมูลจากหน้าเว็บต่างๆ อย่างเป็นระบบ\nซึ่งในบริบทนี้ใช้สำหรับการรวบรวม URL และ Path ของเว็บแอปพลิเคชัน\n","text",[102,103,99],"code",{"__ignoreMap":104},"",[17,106,107],{},"เริ่มจากที่เราทำ Web crawling ง่ายๆ ผ่าน code python ดังนี้",[95,109,113],{"className":110,"code":111,"language":112,"meta":104,"style":104},"language-python shiki shiki-themes github-light","import requests\nfrom bs4 import BeautifulSoup\nimport urllib.parse\nimport time\nimport csv\nfrom collections import deque\nimport os\n\nclass WebCrawler:\n    def __init__(self, starting_url, domain_restriction=None, delay=1, max_pages=100):\n        \"\"\"\n        Initialize the web crawler\n\n        Args:\n            starting_url (str): The URL to start crawling from\n            domain_restriction (str, optional): Restrict crawling to this domain only\n            delay (int, optional): Delay between requests in seconds\n            max_pages (int, optional): Maximum number of pages to crawl\n        \"\"\"\n        self.starting_url = starting_url\n        self.visited_urls = set()\n        self.urls_to_visit = deque([starting_url])\n        self.delay = delay\n        self.max_pages = max_pages\n\n        # Extract domain from starting URL if not provided\n        if domain_restriction is None:\n            parsed_url = urllib.parse.urlparse(starting_url)\n            self.domain_restriction = parsed_url.netloc\n        else:\n            self.domain_restriction = domain_restriction\n\n        self.data = []\n        self.headers = {\n            'User-Agent': 'Mozilla\u002F5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\u002F537.36 (KHTML, like Gecko) Chrome\u002F91.0.4472.124 Safari\u002F537.36'\n        }\n\n    def is_valid_url(self, url):\n        \"\"\"Check if URL should be crawled\"\"\"\n        parsed_url = urllib.parse.urlparse(url)\n\n        # Check if URL is within allowed domain\n        if self.domain_restriction and parsed_url.netloc != self.domain_restriction:\n            return False\n\n        # Skip non-http(s) URLs\n        if parsed_url.scheme not in ['http', 'https']:\n            return False\n\n        # Skip already visited URLs\n        if url in self.visited_urls:\n            return False\n\n        return True\n\n    def extract_links(self, soup, base_url):\n        \"\"\"Extract all links from a page\"\"\"\n        links = []\n        for link in soup.find_all('a', href=True):\n            href = link['href']\n\n            # Convert relative URLs to absolute URLs\n            absolute_url = urllib.parse.urljoin(base_url, href)\n\n            # Normalize the URL\n            absolute_url = urllib.parse.urldefrag(absolute_url)[0]  # Remove fragments\n\n            if self.is_valid_url(absolute_url):\n                links.append(absolute_url)\n\n        return links\n\n    def extract_data(self, soup, url):\n        \"\"\"\n        Extract relevant data from the page\n        Override this method in subclasses to customize data extraction\n        \"\"\"\n        title = soup.title.text.strip() if soup.title else \"No Title\"\n\n        # Example: extract all paragraph text\n        paragraphs = [p.text.strip() for p in soup.find_all('p')]\n\n        # Example: extract metadata\n        meta_description = \"\"\n        meta_tag = soup.find(\"meta\", attrs={\"name\": \"description\"})\n        if meta_tag and \"content\" in meta_tag.attrs:\n            meta_description = meta_tag[\"content\"]\n\n        return {\n            \"url\": url,\n            \"title\": title,\n            \"meta_description\": meta_description,\n            \"paragraph_count\": len(paragraphs),\n            \"first_paragraph\": paragraphs[0] if paragraphs else \"\"\n        }\n\n    def crawl(self):\n        \"\"\"Start the crawling process\"\"\"\n        count = 0\n\n        while self.urls_to_visit and count \u003C self.max_pages:\n            # Get the next URL to visit\n            url = self.urls_to_visit.popleft()\n\n            # Skip if already visited\n            if url in self.visited_urls:\n                continue\n\n            print(f\"Crawling: {url}\")\n\n            try:\n                # Make the request\n                response = requests.get(url, headers=self.headers, timeout=10)\n\n                # Check if request was successful\n                if response.status_code == 200:\n                    # Mark as visited\n                    self.visited_urls.add(url)\n                    count += 1\n\n                    # Parse HTML\n                    soup = BeautifulSoup(response.text, 'html.parser')\n\n                    # Extract data\n                    page_data = self.extract_data(soup, url)\n                    self.data.append(page_data)\n\n                    # Extract links and add to queue\n                    links = self.extract_links(soup, url)\n                    for link in links:\n                        if link not in self.visited_urls:\n                            self.urls_to_visit.append(link)\n\n                    # Respect robots.txt by adding delay\n                    time.sleep(self.delay)\n                else:\n                    print(f\"Failed to retrieve {url}: Status code {response.status_code}\")\n\n            except Exception as e:\n                print(f\"Error crawling {url}: {str(e)}\")\n\n        print(f\"Crawling complete. Visited {len(self.visited_urls)} pages.\")\n\n    def save_data_to_csv(self, filename=\"crawl_results.csv\"):\n        \"\"\"Save the extracted data to a CSV file\"\"\"\n        if not self.data:\n            print(\"No data to save.\")\n            return\n\n        # Get all unique keys from all dictionaries\n        fieldnames = set()\n        for item in self.data:\n            fieldnames.update(item.keys())\n\n        with open(filename, 'w', newline='', encoding='utf-8') as csvfile:\n            writer = csv.DictWriter(csvfile, fieldnames=fieldnames)\n            writer.writeheader()\n            writer.writerows(self.data)\n\n        print(f\"Data saved to {filename}\")\n\n# Example usage\nif __name__ == \"__main__\":\n    # Create a custom crawler class by extending WebCrawler\n    class NewsCrawler(WebCrawler):\n        def extract_data(self, soup, url):\n            \"\"\"Custom data extraction for news sites\"\"\"\n            title = soup.title.text.strip() if soup.title else \"No Title\"\n\n            # Find article content\n            article = soup.find('article')\n            content = \"\"\n            if article:\n                paragraphs = article.find_all('p')\n                content = \" \".join([p.text.strip() for p in paragraphs])\n\n            # Try to find publication date\n            date_tag = soup.find(\"meta\", attrs={\"property\": \"article:published_time\"})\n            date = date_tag[\"content\"] if date_tag and \"content\" in date_tag.attrs else \"Unknown\"\n\n            return {\n                \"url\": url,\n                \"title\": title,\n                \"publication_date\": date,\n                \"content_preview\": content[:200] + \"...\" if content else \"\",\n                \"word_count\": len(content.split()) if content else 0\n            }\n\n    # Create and run the crawler\n    # Replace with the website you want to crawl\n    crawler = NewsCrawler(\n        starting_url=\"https:\u002F\u002Fexample.com\",\n        domain_restriction=\"example.com\",\n        delay=2,  # Be respectful with delay between requests\n        max_pages=20  # Limit number of pages to crawl\n    )\n\n    crawler.crawl()\n    crawler.save_data_to_csv(\"news_results.csv\")\n","python",[102,114,115,128,142,150,158,166,179,187,194,207,245,252,258,263,269,275,281,287,293,298,312,328,341,354,367,372,379,396,407,421,429,441,446,459,472,484,490,495,506,512,523,528,534,558,567,572,578,607,614,619,625,641,648,653,662,667,678,684,694,724,741,746,752,763,768,774,793,798,809,815,820,828,833,844,849,855,861,866,889,894,900,927,932,938,949,984,1002,1018,1023,1030,1039,1048,1057,1071,1094,1099,1104,1115,1121,1132,1137,1160,1166,1179,1184,1190,1203,1209,1214,1243,1248,1256,1262,1294,1299,1305,1322,1328,1337,1349,1354,1360,1376,1381,1387,1400,1408,1413,1419,1432,1445,1461,1470,1475,1481,1492,1500,1533,1538,1553,1586,1591,1621,1626,1644,1650,1663,1675,1681,1686,1692,1704,1718,1724,1729,1773,1792,1798,1809,1814,1837,1842,1848,1864,1870,1886,1896,1902,1920,1925,1931,1946,1956,1964,1979,2002,2007,2013,2043,2077,2082,2089,2097,2105,2114,2148,2169,2175,2180,2186,2192,2203,2216,2229,2246,2260,2266,2271,2277],{"__ignoreMap":104},[116,117,120,124],"span",{"class":118,"line":119},"line",1,[116,121,123],{"class":122},"sD7c4","import",[116,125,127],{"class":126},"sgsFI"," requests\n",[116,129,131,134,137,139],{"class":118,"line":130},2,[116,132,133],{"class":122},"from",[116,135,136],{"class":126}," bs4 ",[116,138,123],{"class":122},[116,140,141],{"class":126}," BeautifulSoup\n",[116,143,145,147],{"class":118,"line":144},3,[116,146,123],{"class":122},[116,148,149],{"class":126}," urllib.parse\n",[116,151,153,155],{"class":118,"line":152},4,[116,154,123],{"class":122},[116,156,157],{"class":126}," time\n",[116,159,161,163],{"class":118,"line":160},5,[116,162,123],{"class":122},[116,164,165],{"class":126}," csv\n",[116,167,169,171,174,176],{"class":118,"line":168},6,[116,170,133],{"class":122},[116,172,173],{"class":126}," collections ",[116,175,123],{"class":122},[116,177,178],{"class":126}," deque\n",[116,180,182,184],{"class":118,"line":181},7,[116,183,123],{"class":122},[116,185,186],{"class":126}," os\n",[116,188,190],{"class":118,"line":189},8,[116,191,193],{"emptyLinePlaceholder":192},true,"\n",[116,195,197,200,204],{"class":118,"line":196},9,[116,198,199],{"class":122},"class",[116,201,203],{"class":202},"s7eDp"," WebCrawler",[116,205,206],{"class":126},":\n",[116,208,210,213,217,220,223,226,229,231,234,237,239,242],{"class":118,"line":209},10,[116,211,212],{"class":122},"    def",[116,214,216],{"class":215},"sYu0t"," __init__",[116,218,219],{"class":126},"(self, starting_url, domain_restriction",[116,221,222],{"class":122},"=",[116,224,225],{"class":215},"None",[116,227,228],{"class":126},", delay",[116,230,222],{"class":122},[116,232,233],{"class":215},"1",[116,235,236],{"class":126},", max_pages",[116,238,222],{"class":122},[116,240,241],{"class":215},"100",[116,243,244],{"class":126},"):\n",[116,246,248],{"class":118,"line":247},11,[116,249,251],{"class":250},"sYBdl","        \"\"\"\n",[116,253,255],{"class":118,"line":254},12,[116,256,257],{"class":250},"        Initialize the web crawler\n",[116,259,261],{"class":118,"line":260},13,[116,262,193],{"emptyLinePlaceholder":192},[116,264,266],{"class":118,"line":265},14,[116,267,268],{"class":250},"        Args:\n",[116,270,272],{"class":118,"line":271},15,[116,273,274],{"class":250},"            starting_url (str): The URL to start crawling from\n",[116,276,278],{"class":118,"line":277},16,[116,279,280],{"class":250},"            domain_restriction (str, optional): Restrict crawling to this domain only\n",[116,282,284],{"class":118,"line":283},17,[116,285,286],{"class":250},"            delay (int, optional): Delay between requests in seconds\n",[116,288,290],{"class":118,"line":289},18,[116,291,292],{"class":250},"            max_pages (int, optional): Maximum number of pages to crawl\n",[116,294,296],{"class":118,"line":295},19,[116,297,251],{"class":250},[116,299,301,304,307,309],{"class":118,"line":300},20,[116,302,303],{"class":215},"        self",[116,305,306],{"class":126},".starting_url ",[116,308,222],{"class":122},[116,310,311],{"class":126}," starting_url\n",[116,313,315,317,320,322,325],{"class":118,"line":314},21,[116,316,303],{"class":215},[116,318,319],{"class":126},".visited_urls ",[116,321,222],{"class":122},[116,323,324],{"class":215}," set",[116,326,327],{"class":126},"()\n",[116,329,331,333,336,338],{"class":118,"line":330},22,[116,332,303],{"class":215},[116,334,335],{"class":126},".urls_to_visit ",[116,337,222],{"class":122},[116,339,340],{"class":126}," deque([starting_url])\n",[116,342,344,346,349,351],{"class":118,"line":343},23,[116,345,303],{"class":215},[116,347,348],{"class":126},".delay ",[116,350,222],{"class":122},[116,352,353],{"class":126}," delay\n",[116,355,357,359,362,364],{"class":118,"line":356},24,[116,358,303],{"class":215},[116,360,361],{"class":126},".max_pages ",[116,363,222],{"class":122},[116,365,366],{"class":126}," max_pages\n",[116,368,370],{"class":118,"line":369},25,[116,371,193],{"emptyLinePlaceholder":192},[116,373,375],{"class":118,"line":374},26,[116,376,378],{"class":377},"sAwPA","        # Extract domain from starting URL if not provided\n",[116,380,382,385,388,391,394],{"class":118,"line":381},27,[116,383,384],{"class":122},"        if",[116,386,387],{"class":126}," domain_restriction ",[116,389,390],{"class":122},"is",[116,392,393],{"class":215}," None",[116,395,206],{"class":126},[116,397,399,402,404],{"class":118,"line":398},28,[116,400,401],{"class":126},"            parsed_url ",[116,403,222],{"class":122},[116,405,406],{"class":126}," urllib.parse.urlparse(starting_url)\n",[116,408,410,413,416,418],{"class":118,"line":409},29,[116,411,412],{"class":215},"            self",[116,414,415],{"class":126},".domain_restriction ",[116,417,222],{"class":122},[116,419,420],{"class":126}," parsed_url.netloc\n",[116,422,424,427],{"class":118,"line":423},30,[116,425,426],{"class":122},"        else",[116,428,206],{"class":126},[116,430,432,434,436,438],{"class":118,"line":431},31,[116,433,412],{"class":215},[116,435,415],{"class":126},[116,437,222],{"class":122},[116,439,440],{"class":126}," domain_restriction\n",[116,442,444],{"class":118,"line":443},32,[116,445,193],{"emptyLinePlaceholder":192},[116,447,449,451,454,456],{"class":118,"line":448},33,[116,450,303],{"class":215},[116,452,453],{"class":126},".data ",[116,455,222],{"class":122},[116,457,458],{"class":126}," []\n",[116,460,462,464,467,469],{"class":118,"line":461},34,[116,463,303],{"class":215},[116,465,466],{"class":126},".headers ",[116,468,222],{"class":122},[116,470,471],{"class":126}," {\n",[116,473,475,478,481],{"class":118,"line":474},35,[116,476,477],{"class":250},"            'User-Agent'",[116,479,480],{"class":126},": ",[116,482,483],{"class":250},"'Mozilla\u002F5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\u002F537.36 (KHTML, like Gecko) Chrome\u002F91.0.4472.124 Safari\u002F537.36'\n",[116,485,487],{"class":118,"line":486},36,[116,488,489],{"class":126},"        }\n",[116,491,493],{"class":118,"line":492},37,[116,494,193],{"emptyLinePlaceholder":192},[116,496,498,500,503],{"class":118,"line":497},38,[116,499,212],{"class":122},[116,501,502],{"class":202}," is_valid_url",[116,504,505],{"class":126},"(self, url):\n",[116,507,509],{"class":118,"line":508},39,[116,510,511],{"class":250},"        \"\"\"Check if URL should be crawled\"\"\"\n",[116,513,515,518,520],{"class":118,"line":514},40,[116,516,517],{"class":126},"        parsed_url ",[116,519,222],{"class":122},[116,521,522],{"class":126}," urllib.parse.urlparse(url)\n",[116,524,526],{"class":118,"line":525},41,[116,527,193],{"emptyLinePlaceholder":192},[116,529,531],{"class":118,"line":530},42,[116,532,533],{"class":377},"        # Check if URL is within allowed domain\n",[116,535,537,539,542,544,547,550,553,555],{"class":118,"line":536},43,[116,538,384],{"class":122},[116,540,541],{"class":215}," self",[116,543,415],{"class":126},[116,545,546],{"class":122},"and",[116,548,549],{"class":126}," parsed_url.netloc ",[116,551,552],{"class":122},"!=",[116,554,541],{"class":215},[116,556,557],{"class":126},".domain_restriction:\n",[116,559,561,564],{"class":118,"line":560},44,[116,562,563],{"class":122},"            return",[116,565,566],{"class":215}," False\n",[116,568,570],{"class":118,"line":569},45,[116,571,193],{"emptyLinePlaceholder":192},[116,573,575],{"class":118,"line":574},46,[116,576,577],{"class":377},"        # Skip non-http(s) URLs\n",[116,579,581,583,586,589,592,595,598,601,604],{"class":118,"line":580},47,[116,582,384],{"class":122},[116,584,585],{"class":126}," parsed_url.scheme ",[116,587,588],{"class":122},"not",[116,590,591],{"class":122}," in",[116,593,594],{"class":126}," [",[116,596,597],{"class":250},"'http'",[116,599,600],{"class":126},", ",[116,602,603],{"class":250},"'https'",[116,605,606],{"class":126},"]:\n",[116,608,610,612],{"class":118,"line":609},48,[116,611,563],{"class":122},[116,613,566],{"class":215},[116,615,617],{"class":118,"line":616},49,[116,618,193],{"emptyLinePlaceholder":192},[116,620,622],{"class":118,"line":621},50,[116,623,624],{"class":377},"        # Skip already visited URLs\n",[116,626,628,630,633,636,638],{"class":118,"line":627},51,[116,629,384],{"class":122},[116,631,632],{"class":126}," url ",[116,634,635],{"class":122},"in",[116,637,541],{"class":215},[116,639,640],{"class":126},".visited_urls:\n",[116,642,644,646],{"class":118,"line":643},52,[116,645,563],{"class":122},[116,647,566],{"class":215},[116,649,651],{"class":118,"line":650},53,[116,652,193],{"emptyLinePlaceholder":192},[116,654,656,659],{"class":118,"line":655},54,[116,657,658],{"class":122},"        return",[116,660,661],{"class":215}," True\n",[116,663,665],{"class":118,"line":664},55,[116,666,193],{"emptyLinePlaceholder":192},[116,668,670,672,675],{"class":118,"line":669},56,[116,671,212],{"class":122},[116,673,674],{"class":202}," extract_links",[116,676,677],{"class":126},"(self, soup, base_url):\n",[116,679,681],{"class":118,"line":680},57,[116,682,683],{"class":250},"        \"\"\"Extract all links from a page\"\"\"\n",[116,685,687,690,692],{"class":118,"line":686},58,[116,688,689],{"class":126},"        links ",[116,691,222],{"class":122},[116,693,458],{"class":126},[116,695,697,700,703,705,708,711,713,717,719,722],{"class":118,"line":696},59,[116,698,699],{"class":122},"        for",[116,701,702],{"class":126}," link ",[116,704,635],{"class":122},[116,706,707],{"class":126}," soup.find_all(",[116,709,710],{"class":250},"'a'",[116,712,600],{"class":126},[116,714,716],{"class":715},"sqxcx","href",[116,718,222],{"class":122},[116,720,721],{"class":215},"True",[116,723,244],{"class":126},[116,725,727,730,732,735,738],{"class":118,"line":726},60,[116,728,729],{"class":126},"            href ",[116,731,222],{"class":122},[116,733,734],{"class":126}," link[",[116,736,737],{"class":250},"'href'",[116,739,740],{"class":126},"]\n",[116,742,744],{"class":118,"line":743},61,[116,745,193],{"emptyLinePlaceholder":192},[116,747,749],{"class":118,"line":748},62,[116,750,751],{"class":377},"            # Convert relative URLs to absolute URLs\n",[116,753,755,758,760],{"class":118,"line":754},63,[116,756,757],{"class":126},"            absolute_url ",[116,759,222],{"class":122},[116,761,762],{"class":126}," urllib.parse.urljoin(base_url, href)\n",[116,764,766],{"class":118,"line":765},64,[116,767,193],{"emptyLinePlaceholder":192},[116,769,771],{"class":118,"line":770},65,[116,772,773],{"class":377},"            # Normalize the URL\n",[116,775,777,779,781,784,787,790],{"class":118,"line":776},66,[116,778,757],{"class":126},[116,780,222],{"class":122},[116,782,783],{"class":126}," urllib.parse.urldefrag(absolute_url)[",[116,785,786],{"class":215},"0",[116,788,789],{"class":126},"]  ",[116,791,792],{"class":377},"# Remove fragments\n",[116,794,796],{"class":118,"line":795},67,[116,797,193],{"emptyLinePlaceholder":192},[116,799,801,804,806],{"class":118,"line":800},68,[116,802,803],{"class":122},"            if",[116,805,541],{"class":215},[116,807,808],{"class":126},".is_valid_url(absolute_url):\n",[116,810,812],{"class":118,"line":811},69,[116,813,814],{"class":126},"                links.append(absolute_url)\n",[116,816,818],{"class":118,"line":817},70,[116,819,193],{"emptyLinePlaceholder":192},[116,821,823,825],{"class":118,"line":822},71,[116,824,658],{"class":122},[116,826,827],{"class":126}," links\n",[116,829,831],{"class":118,"line":830},72,[116,832,193],{"emptyLinePlaceholder":192},[116,834,836,838,841],{"class":118,"line":835},73,[116,837,212],{"class":122},[116,839,840],{"class":202}," extract_data",[116,842,843],{"class":126},"(self, soup, url):\n",[116,845,847],{"class":118,"line":846},74,[116,848,251],{"class":250},[116,850,852],{"class":118,"line":851},75,[116,853,854],{"class":250},"        Extract relevant data from the page\n",[116,856,858],{"class":118,"line":857},76,[116,859,860],{"class":250},"        Override this method in subclasses to customize data extraction\n",[116,862,864],{"class":118,"line":863},77,[116,865,251],{"class":250},[116,867,869,872,874,877,880,883,886],{"class":118,"line":868},78,[116,870,871],{"class":126},"        title ",[116,873,222],{"class":122},[116,875,876],{"class":126}," soup.title.text.strip() ",[116,878,879],{"class":122},"if",[116,881,882],{"class":126}," soup.title ",[116,884,885],{"class":122},"else",[116,887,888],{"class":250}," \"No Title\"\n",[116,890,892],{"class":118,"line":891},79,[116,893,193],{"emptyLinePlaceholder":192},[116,895,897],{"class":118,"line":896},80,[116,898,899],{"class":377},"        # Example: extract all paragraph text\n",[116,901,903,906,908,911,914,917,919,921,924],{"class":118,"line":902},81,[116,904,905],{"class":126},"        paragraphs ",[116,907,222],{"class":122},[116,909,910],{"class":126}," [p.text.strip() ",[116,912,913],{"class":122},"for",[116,915,916],{"class":126}," p ",[116,918,635],{"class":122},[116,920,707],{"class":126},[116,922,923],{"class":250},"'p'",[116,925,926],{"class":126},")]\n",[116,928,930],{"class":118,"line":929},82,[116,931,193],{"emptyLinePlaceholder":192},[116,933,935],{"class":118,"line":934},83,[116,936,937],{"class":377},"        # Example: extract metadata\n",[116,939,941,944,946],{"class":118,"line":940},84,[116,942,943],{"class":126},"        meta_description ",[116,945,222],{"class":122},[116,947,948],{"class":250}," \"\"\n",[116,950,952,955,957,960,963,965,968,970,973,976,978,981],{"class":118,"line":951},85,[116,953,954],{"class":126},"        meta_tag ",[116,956,222],{"class":122},[116,958,959],{"class":126}," soup.find(",[116,961,962],{"class":250},"\"meta\"",[116,964,600],{"class":126},[116,966,967],{"class":715},"attrs",[116,969,222],{"class":122},[116,971,972],{"class":126},"{",[116,974,975],{"class":250},"\"name\"",[116,977,480],{"class":126},[116,979,980],{"class":250},"\"description\"",[116,982,983],{"class":126},"})\n",[116,985,987,989,992,994,997,999],{"class":118,"line":986},86,[116,988,384],{"class":122},[116,990,991],{"class":126}," meta_tag ",[116,993,546],{"class":122},[116,995,996],{"class":250}," \"content\"",[116,998,591],{"class":122},[116,1000,1001],{"class":126}," meta_tag.attrs:\n",[116,1003,1005,1008,1010,1013,1016],{"class":118,"line":1004},87,[116,1006,1007],{"class":126},"            meta_description ",[116,1009,222],{"class":122},[116,1011,1012],{"class":126}," meta_tag[",[116,1014,1015],{"class":250},"\"content\"",[116,1017,740],{"class":126},[116,1019,1021],{"class":118,"line":1020},88,[116,1022,193],{"emptyLinePlaceholder":192},[116,1024,1026,1028],{"class":118,"line":1025},89,[116,1027,658],{"class":122},[116,1029,471],{"class":126},[116,1031,1033,1036],{"class":118,"line":1032},90,[116,1034,1035],{"class":250},"            \"url\"",[116,1037,1038],{"class":126},": url,\n",[116,1040,1042,1045],{"class":118,"line":1041},91,[116,1043,1044],{"class":250},"            \"title\"",[116,1046,1047],{"class":126},": title,\n",[116,1049,1051,1054],{"class":118,"line":1050},92,[116,1052,1053],{"class":250},"            \"meta_description\"",[116,1055,1056],{"class":126},": meta_description,\n",[116,1058,1060,1063,1065,1068],{"class":118,"line":1059},93,[116,1061,1062],{"class":250},"            \"paragraph_count\"",[116,1064,480],{"class":126},[116,1066,1067],{"class":215},"len",[116,1069,1070],{"class":126},"(paragraphs),\n",[116,1072,1074,1077,1080,1082,1085,1087,1090,1092],{"class":118,"line":1073},94,[116,1075,1076],{"class":250},"            \"first_paragraph\"",[116,1078,1079],{"class":126},": paragraphs[",[116,1081,786],{"class":215},[116,1083,1084],{"class":126},"] ",[116,1086,879],{"class":122},[116,1088,1089],{"class":126}," paragraphs ",[116,1091,885],{"class":122},[116,1093,948],{"class":250},[116,1095,1097],{"class":118,"line":1096},95,[116,1098,489],{"class":126},[116,1100,1102],{"class":118,"line":1101},96,[116,1103,193],{"emptyLinePlaceholder":192},[116,1105,1107,1109,1112],{"class":118,"line":1106},97,[116,1108,212],{"class":122},[116,1110,1111],{"class":202}," crawl",[116,1113,1114],{"class":126},"(self):\n",[116,1116,1118],{"class":118,"line":1117},98,[116,1119,1120],{"class":250},"        \"\"\"Start the crawling process\"\"\"\n",[116,1122,1124,1127,1129],{"class":118,"line":1123},99,[116,1125,1126],{"class":126},"        count ",[116,1128,222],{"class":122},[116,1130,1131],{"class":215}," 0\n",[116,1133,1135],{"class":118,"line":1134},100,[116,1136,193],{"emptyLinePlaceholder":192},[116,1138,1140,1143,1145,1147,1149,1152,1155,1157],{"class":118,"line":1139},101,[116,1141,1142],{"class":122},"        while",[116,1144,541],{"class":215},[116,1146,335],{"class":126},[116,1148,546],{"class":122},[116,1150,1151],{"class":126}," count ",[116,1153,1154],{"class":122},"\u003C",[116,1156,541],{"class":215},[116,1158,1159],{"class":126},".max_pages:\n",[116,1161,1163],{"class":118,"line":1162},102,[116,1164,1165],{"class":377},"            # Get the next URL to visit\n",[116,1167,1169,1172,1174,1176],{"class":118,"line":1168},103,[116,1170,1171],{"class":126},"            url ",[116,1173,222],{"class":122},[116,1175,541],{"class":215},[116,1177,1178],{"class":126},".urls_to_visit.popleft()\n",[116,1180,1182],{"class":118,"line":1181},104,[116,1183,193],{"emptyLinePlaceholder":192},[116,1185,1187],{"class":118,"line":1186},105,[116,1188,1189],{"class":377},"            # Skip if already visited\n",[116,1191,1193,1195,1197,1199,1201],{"class":118,"line":1192},106,[116,1194,803],{"class":122},[116,1196,632],{"class":126},[116,1198,635],{"class":122},[116,1200,541],{"class":215},[116,1202,640],{"class":126},[116,1204,1206],{"class":118,"line":1205},107,[116,1207,1208],{"class":122},"                continue\n",[116,1210,1212],{"class":118,"line":1211},108,[116,1213,193],{"emptyLinePlaceholder":192},[116,1215,1217,1220,1223,1226,1229,1231,1234,1237,1240],{"class":118,"line":1216},109,[116,1218,1219],{"class":215},"            print",[116,1221,1222],{"class":126},"(",[116,1224,1225],{"class":122},"f",[116,1227,1228],{"class":250},"\"Crawling: ",[116,1230,972],{"class":215},[116,1232,1233],{"class":126},"url",[116,1235,1236],{"class":215},"}",[116,1238,1239],{"class":250},"\"",[116,1241,1242],{"class":126},")\n",[116,1244,1246],{"class":118,"line":1245},110,[116,1247,193],{"emptyLinePlaceholder":192},[116,1249,1251,1254],{"class":118,"line":1250},111,[116,1252,1253],{"class":122},"            try",[116,1255,206],{"class":126},[116,1257,1259],{"class":118,"line":1258},112,[116,1260,1261],{"class":377},"                # Make the request\n",[116,1263,1265,1268,1270,1273,1276,1278,1281,1284,1287,1289,1292],{"class":118,"line":1264},113,[116,1266,1267],{"class":126},"                response ",[116,1269,222],{"class":122},[116,1271,1272],{"class":126}," requests.get(url, ",[116,1274,1275],{"class":715},"headers",[116,1277,222],{"class":122},[116,1279,1280],{"class":215},"self",[116,1282,1283],{"class":126},".headers, ",[116,1285,1286],{"class":715},"timeout",[116,1288,222],{"class":122},[116,1290,1291],{"class":215},"10",[116,1293,1242],{"class":126},[116,1295,1297],{"class":118,"line":1296},114,[116,1298,193],{"emptyLinePlaceholder":192},[116,1300,1302],{"class":118,"line":1301},115,[116,1303,1304],{"class":377},"                # Check if request was successful\n",[116,1306,1308,1311,1314,1317,1320],{"class":118,"line":1307},116,[116,1309,1310],{"class":122},"                if",[116,1312,1313],{"class":126}," response.status_code ",[116,1315,1316],{"class":122},"==",[116,1318,1319],{"class":215}," 200",[116,1321,206],{"class":126},[116,1323,1325],{"class":118,"line":1324},117,[116,1326,1327],{"class":377},"                    # Mark as visited\n",[116,1329,1331,1334],{"class":118,"line":1330},118,[116,1332,1333],{"class":215},"                    self",[116,1335,1336],{"class":126},".visited_urls.add(url)\n",[116,1338,1340,1343,1346],{"class":118,"line":1339},119,[116,1341,1342],{"class":126},"                    count ",[116,1344,1345],{"class":122},"+=",[116,1347,1348],{"class":215}," 1\n",[116,1350,1352],{"class":118,"line":1351},120,[116,1353,193],{"emptyLinePlaceholder":192},[116,1355,1357],{"class":118,"line":1356},121,[116,1358,1359],{"class":377},"                    # Parse HTML\n",[116,1361,1363,1366,1368,1371,1374],{"class":118,"line":1362},122,[116,1364,1365],{"class":126},"                    soup ",[116,1367,222],{"class":122},[116,1369,1370],{"class":126}," BeautifulSoup(response.text, ",[116,1372,1373],{"class":250},"'html.parser'",[116,1375,1242],{"class":126},[116,1377,1379],{"class":118,"line":1378},123,[116,1380,193],{"emptyLinePlaceholder":192},[116,1382,1384],{"class":118,"line":1383},124,[116,1385,1386],{"class":377},"                    # Extract data\n",[116,1388,1390,1393,1395,1397],{"class":118,"line":1389},125,[116,1391,1392],{"class":126},"                    page_data ",[116,1394,222],{"class":122},[116,1396,541],{"class":215},[116,1398,1399],{"class":126},".extract_data(soup, url)\n",[116,1401,1403,1405],{"class":118,"line":1402},126,[116,1404,1333],{"class":215},[116,1406,1407],{"class":126},".data.append(page_data)\n",[116,1409,1411],{"class":118,"line":1410},127,[116,1412,193],{"emptyLinePlaceholder":192},[116,1414,1416],{"class":118,"line":1415},128,[116,1417,1418],{"class":377},"                    # Extract links and add to queue\n",[116,1420,1422,1425,1427,1429],{"class":118,"line":1421},129,[116,1423,1424],{"class":126},"                    links ",[116,1426,222],{"class":122},[116,1428,541],{"class":215},[116,1430,1431],{"class":126},".extract_links(soup, url)\n",[116,1433,1435,1438,1440,1442],{"class":118,"line":1434},130,[116,1436,1437],{"class":122},"                    for",[116,1439,702],{"class":126},[116,1441,635],{"class":122},[116,1443,1444],{"class":126}," links:\n",[116,1446,1448,1451,1453,1455,1457,1459],{"class":118,"line":1447},131,[116,1449,1450],{"class":122},"                        if",[116,1452,702],{"class":126},[116,1454,588],{"class":122},[116,1456,591],{"class":122},[116,1458,541],{"class":215},[116,1460,640],{"class":126},[116,1462,1464,1467],{"class":118,"line":1463},132,[116,1465,1466],{"class":215},"                            self",[116,1468,1469],{"class":126},".urls_to_visit.append(link)\n",[116,1471,1473],{"class":118,"line":1472},133,[116,1474,193],{"emptyLinePlaceholder":192},[116,1476,1478],{"class":118,"line":1477},134,[116,1479,1480],{"class":377},"                    # Respect robots.txt by adding delay\n",[116,1482,1484,1487,1489],{"class":118,"line":1483},135,[116,1485,1486],{"class":126},"                    time.sleep(",[116,1488,1280],{"class":215},[116,1490,1491],{"class":126},".delay)\n",[116,1493,1495,1498],{"class":118,"line":1494},136,[116,1496,1497],{"class":122},"                else",[116,1499,206],{"class":126},[116,1501,1503,1506,1508,1510,1513,1515,1517,1519,1522,1524,1527,1529,1531],{"class":118,"line":1502},137,[116,1504,1505],{"class":215},"                    print",[116,1507,1222],{"class":126},[116,1509,1225],{"class":122},[116,1511,1512],{"class":250},"\"Failed to retrieve ",[116,1514,972],{"class":215},[116,1516,1233],{"class":126},[116,1518,1236],{"class":215},[116,1520,1521],{"class":250},": Status code ",[116,1523,972],{"class":215},[116,1525,1526],{"class":126},"response.status_code",[116,1528,1236],{"class":215},[116,1530,1239],{"class":250},[116,1532,1242],{"class":126},[116,1534,1536],{"class":118,"line":1535},138,[116,1537,193],{"emptyLinePlaceholder":192},[116,1539,1541,1544,1547,1550],{"class":118,"line":1540},139,[116,1542,1543],{"class":122},"            except",[116,1545,1546],{"class":215}," Exception",[116,1548,1549],{"class":122}," as",[116,1551,1552],{"class":126}," e:\n",[116,1554,1556,1559,1561,1563,1566,1568,1570,1572,1574,1577,1580,1582,1584],{"class":118,"line":1555},140,[116,1557,1558],{"class":215},"                print",[116,1560,1222],{"class":126},[116,1562,1225],{"class":122},[116,1564,1565],{"class":250},"\"Error crawling ",[116,1567,972],{"class":215},[116,1569,1233],{"class":126},[116,1571,1236],{"class":215},[116,1573,480],{"class":250},[116,1575,1576],{"class":215},"{str",[116,1578,1579],{"class":126},"(e)",[116,1581,1236],{"class":215},[116,1583,1239],{"class":250},[116,1585,1242],{"class":126},[116,1587,1589],{"class":118,"line":1588},141,[116,1590,193],{"emptyLinePlaceholder":192},[116,1592,1594,1597,1599,1601,1604,1607,1609,1611,1614,1616,1619],{"class":118,"line":1593},142,[116,1595,1596],{"class":215},"        print",[116,1598,1222],{"class":126},[116,1600,1225],{"class":122},[116,1602,1603],{"class":250},"\"Crawling complete. Visited ",[116,1605,1606],{"class":215},"{len",[116,1608,1222],{"class":126},[116,1610,1280],{"class":215},[116,1612,1613],{"class":126},".visited_urls)",[116,1615,1236],{"class":215},[116,1617,1618],{"class":250}," pages.\"",[116,1620,1242],{"class":126},[116,1622,1624],{"class":118,"line":1623},143,[116,1625,193],{"emptyLinePlaceholder":192},[116,1627,1629,1631,1634,1637,1639,1642],{"class":118,"line":1628},144,[116,1630,212],{"class":122},[116,1632,1633],{"class":202}," save_data_to_csv",[116,1635,1636],{"class":126},"(self, filename",[116,1638,222],{"class":122},[116,1640,1641],{"class":250},"\"crawl_results.csv\"",[116,1643,244],{"class":126},[116,1645,1647],{"class":118,"line":1646},145,[116,1648,1649],{"class":250},"        \"\"\"Save the extracted data to a CSV file\"\"\"\n",[116,1651,1653,1655,1658,1660],{"class":118,"line":1652},146,[116,1654,384],{"class":122},[116,1656,1657],{"class":122}," not",[116,1659,541],{"class":215},[116,1661,1662],{"class":126},".data:\n",[116,1664,1666,1668,1670,1673],{"class":118,"line":1665},147,[116,1667,1219],{"class":215},[116,1669,1222],{"class":126},[116,1671,1672],{"class":250},"\"No data to save.\"",[116,1674,1242],{"class":126},[116,1676,1678],{"class":118,"line":1677},148,[116,1679,1680],{"class":122},"            return\n",[116,1682,1684],{"class":118,"line":1683},149,[116,1685,193],{"emptyLinePlaceholder":192},[116,1687,1689],{"class":118,"line":1688},150,[116,1690,1691],{"class":377},"        # Get all unique keys from all dictionaries\n",[116,1693,1695,1698,1700,1702],{"class":118,"line":1694},151,[116,1696,1697],{"class":126},"        fieldnames ",[116,1699,222],{"class":122},[116,1701,324],{"class":215},[116,1703,327],{"class":126},[116,1705,1707,1709,1712,1714,1716],{"class":118,"line":1706},152,[116,1708,699],{"class":122},[116,1710,1711],{"class":126}," item ",[116,1713,635],{"class":122},[116,1715,541],{"class":215},[116,1717,1662],{"class":126},[116,1719,1721],{"class":118,"line":1720},153,[116,1722,1723],{"class":126},"            fieldnames.update(item.keys())\n",[116,1725,1727],{"class":118,"line":1726},154,[116,1728,193],{"emptyLinePlaceholder":192},[116,1730,1732,1735,1738,1741,1744,1746,1749,1751,1754,1756,1759,1761,1764,1767,1770],{"class":118,"line":1731},155,[116,1733,1734],{"class":122},"        with",[116,1736,1737],{"class":215}," open",[116,1739,1740],{"class":126},"(filename, ",[116,1742,1743],{"class":250},"'w'",[116,1745,600],{"class":126},[116,1747,1748],{"class":715},"newline",[116,1750,222],{"class":122},[116,1752,1753],{"class":250},"''",[116,1755,600],{"class":126},[116,1757,1758],{"class":715},"encoding",[116,1760,222],{"class":122},[116,1762,1763],{"class":250},"'utf-8'",[116,1765,1766],{"class":126},") ",[116,1768,1769],{"class":122},"as",[116,1771,1772],{"class":126}," csvfile:\n",[116,1774,1776,1779,1781,1784,1787,1789],{"class":118,"line":1775},156,[116,1777,1778],{"class":126},"            writer ",[116,1780,222],{"class":122},[116,1782,1783],{"class":126}," csv.DictWriter(csvfile, ",[116,1785,1786],{"class":715},"fieldnames",[116,1788,222],{"class":122},[116,1790,1791],{"class":126},"fieldnames)\n",[116,1793,1795],{"class":118,"line":1794},157,[116,1796,1797],{"class":126},"            writer.writeheader()\n",[116,1799,1801,1804,1806],{"class":118,"line":1800},158,[116,1802,1803],{"class":126},"            writer.writerows(",[116,1805,1280],{"class":215},[116,1807,1808],{"class":126},".data)\n",[116,1810,1812],{"class":118,"line":1811},159,[116,1813,193],{"emptyLinePlaceholder":192},[116,1815,1817,1819,1821,1823,1826,1828,1831,1833,1835],{"class":118,"line":1816},160,[116,1818,1596],{"class":215},[116,1820,1222],{"class":126},[116,1822,1225],{"class":122},[116,1824,1825],{"class":250},"\"Data saved to ",[116,1827,972],{"class":215},[116,1829,1830],{"class":126},"filename",[116,1832,1236],{"class":215},[116,1834,1239],{"class":250},[116,1836,1242],{"class":126},[116,1838,1840],{"class":118,"line":1839},161,[116,1841,193],{"emptyLinePlaceholder":192},[116,1843,1845],{"class":118,"line":1844},162,[116,1846,1847],{"class":377},"# Example usage\n",[116,1849,1851,1853,1856,1859,1862],{"class":118,"line":1850},163,[116,1852,879],{"class":122},[116,1854,1855],{"class":215}," __name__",[116,1857,1858],{"class":122}," ==",[116,1860,1861],{"class":250}," \"__main__\"",[116,1863,206],{"class":126},[116,1865,1867],{"class":118,"line":1866},164,[116,1868,1869],{"class":377},"    # Create a custom crawler class by extending WebCrawler\n",[116,1871,1873,1876,1879,1881,1884],{"class":118,"line":1872},165,[116,1874,1875],{"class":122},"    class",[116,1877,1878],{"class":202}," NewsCrawler",[116,1880,1222],{"class":126},[116,1882,1883],{"class":202},"WebCrawler",[116,1885,244],{"class":126},[116,1887,1889,1892,1894],{"class":118,"line":1888},166,[116,1890,1891],{"class":122},"        def",[116,1893,840],{"class":202},[116,1895,843],{"class":126},[116,1897,1899],{"class":118,"line":1898},167,[116,1900,1901],{"class":250},"            \"\"\"Custom data extraction for news sites\"\"\"\n",[116,1903,1905,1908,1910,1912,1914,1916,1918],{"class":118,"line":1904},168,[116,1906,1907],{"class":126},"            title ",[116,1909,222],{"class":122},[116,1911,876],{"class":126},[116,1913,879],{"class":122},[116,1915,882],{"class":126},[116,1917,885],{"class":122},[116,1919,888],{"class":250},[116,1921,1923],{"class":118,"line":1922},169,[116,1924,193],{"emptyLinePlaceholder":192},[116,1926,1928],{"class":118,"line":1927},170,[116,1929,1930],{"class":377},"            # Find article content\n",[116,1932,1934,1937,1939,1941,1944],{"class":118,"line":1933},171,[116,1935,1936],{"class":126},"            article ",[116,1938,222],{"class":122},[116,1940,959],{"class":126},[116,1942,1943],{"class":250},"'article'",[116,1945,1242],{"class":126},[116,1947,1949,1952,1954],{"class":118,"line":1948},172,[116,1950,1951],{"class":126},"            content ",[116,1953,222],{"class":122},[116,1955,948],{"class":250},[116,1957,1959,1961],{"class":118,"line":1958},173,[116,1960,803],{"class":122},[116,1962,1963],{"class":126}," article:\n",[116,1965,1967,1970,1972,1975,1977],{"class":118,"line":1966},174,[116,1968,1969],{"class":126},"                paragraphs ",[116,1971,222],{"class":122},[116,1973,1974],{"class":126}," article.find_all(",[116,1976,923],{"class":250},[116,1978,1242],{"class":126},[116,1980,1982,1985,1987,1990,1993,1995,1997,1999],{"class":118,"line":1981},175,[116,1983,1984],{"class":126},"                content ",[116,1986,222],{"class":122},[116,1988,1989],{"class":250}," \" \"",[116,1991,1992],{"class":126},".join([p.text.strip() ",[116,1994,913],{"class":122},[116,1996,916],{"class":126},[116,1998,635],{"class":122},[116,2000,2001],{"class":126}," paragraphs])\n",[116,2003,2005],{"class":118,"line":2004},176,[116,2006,193],{"emptyLinePlaceholder":192},[116,2008,2010],{"class":118,"line":2009},177,[116,2011,2012],{"class":377},"            # Try to find publication date\n",[116,2014,2016,2019,2021,2023,2025,2027,2029,2031,2033,2036,2038,2041],{"class":118,"line":2015},178,[116,2017,2018],{"class":126},"            date_tag ",[116,2020,222],{"class":122},[116,2022,959],{"class":126},[116,2024,962],{"class":250},[116,2026,600],{"class":126},[116,2028,967],{"class":715},[116,2030,222],{"class":122},[116,2032,972],{"class":126},[116,2034,2035],{"class":250},"\"property\"",[116,2037,480],{"class":126},[116,2039,2040],{"class":250},"\"article:published_time\"",[116,2042,983],{"class":126},[116,2044,2046,2049,2051,2054,2056,2058,2060,2063,2065,2067,2069,2072,2074],{"class":118,"line":2045},179,[116,2047,2048],{"class":126},"            date ",[116,2050,222],{"class":122},[116,2052,2053],{"class":126}," date_tag[",[116,2055,1015],{"class":250},[116,2057,1084],{"class":126},[116,2059,879],{"class":122},[116,2061,2062],{"class":126}," date_tag ",[116,2064,546],{"class":122},[116,2066,996],{"class":250},[116,2068,591],{"class":122},[116,2070,2071],{"class":126}," date_tag.attrs ",[116,2073,885],{"class":122},[116,2075,2076],{"class":250}," \"Unknown\"\n",[116,2078,2080],{"class":118,"line":2079},180,[116,2081,193],{"emptyLinePlaceholder":192},[116,2083,2085,2087],{"class":118,"line":2084},181,[116,2086,563],{"class":122},[116,2088,471],{"class":126},[116,2090,2092,2095],{"class":118,"line":2091},182,[116,2093,2094],{"class":250},"                \"url\"",[116,2096,1038],{"class":126},[116,2098,2100,2103],{"class":118,"line":2099},183,[116,2101,2102],{"class":250},"                \"title\"",[116,2104,1047],{"class":126},[116,2106,2108,2111],{"class":118,"line":2107},184,[116,2109,2110],{"class":250},"                \"publication_date\"",[116,2112,2113],{"class":126},": date,\n",[116,2115,2117,2120,2123,2126,2128,2131,2134,2137,2140,2142,2145],{"class":118,"line":2116},185,[116,2118,2119],{"class":250},"                \"content_preview\"",[116,2121,2122],{"class":126},": content[:",[116,2124,2125],{"class":215},"200",[116,2127,1084],{"class":126},[116,2129,2130],{"class":122},"+",[116,2132,2133],{"class":250}," \"...\"",[116,2135,2136],{"class":122}," if",[116,2138,2139],{"class":126}," content ",[116,2141,885],{"class":122},[116,2143,2144],{"class":250}," \"\"",[116,2146,2147],{"class":126},",\n",[116,2149,2151,2154,2156,2158,2161,2163,2165,2167],{"class":118,"line":2150},186,[116,2152,2153],{"class":250},"                \"word_count\"",[116,2155,480],{"class":126},[116,2157,1067],{"class":215},[116,2159,2160],{"class":126},"(content.split()) ",[116,2162,879],{"class":122},[116,2164,2139],{"class":126},[116,2166,885],{"class":122},[116,2168,1131],{"class":215},[116,2170,2172],{"class":118,"line":2171},187,[116,2173,2174],{"class":126},"            }\n",[116,2176,2178],{"class":118,"line":2177},188,[116,2179,193],{"emptyLinePlaceholder":192},[116,2181,2183],{"class":118,"line":2182},189,[116,2184,2185],{"class":377},"    # Create and run the crawler\n",[116,2187,2189],{"class":118,"line":2188},190,[116,2190,2191],{"class":377},"    # Replace with the website you want to crawl\n",[116,2193,2195,2198,2200],{"class":118,"line":2194},191,[116,2196,2197],{"class":126},"    crawler ",[116,2199,222],{"class":122},[116,2201,2202],{"class":126}," NewsCrawler(\n",[116,2204,2206,2209,2211,2214],{"class":118,"line":2205},192,[116,2207,2208],{"class":715},"        starting_url",[116,2210,222],{"class":122},[116,2212,2213],{"class":250},"\"https:\u002F\u002Fexample.com\"",[116,2215,2147],{"class":126},[116,2217,2219,2222,2224,2227],{"class":118,"line":2218},193,[116,2220,2221],{"class":715},"        domain_restriction",[116,2223,222],{"class":122},[116,2225,2226],{"class":250},"\"example.com\"",[116,2228,2147],{"class":126},[116,2230,2232,2235,2237,2240,2243],{"class":118,"line":2231},194,[116,2233,2234],{"class":715},"        delay",[116,2236,222],{"class":122},[116,2238,2239],{"class":215},"2",[116,2241,2242],{"class":126},",  ",[116,2244,2245],{"class":377},"# Be respectful with delay between requests\n",[116,2247,2249,2252,2254,2257],{"class":118,"line":2248},195,[116,2250,2251],{"class":715},"        max_pages",[116,2253,222],{"class":122},[116,2255,2256],{"class":215},"20",[116,2258,2259],{"class":377},"  # Limit number of pages to crawl\n",[116,2261,2263],{"class":118,"line":2262},196,[116,2264,2265],{"class":126},"    )\n",[116,2267,2269],{"class":118,"line":2268},197,[116,2270,193],{"emptyLinePlaceholder":192},[116,2272,2274],{"class":118,"line":2273},198,[116,2275,2276],{"class":126},"    crawler.crawl()\n",[116,2278,2280,2283,2286],{"class":118,"line":2279},199,[116,2281,2282],{"class":126},"    crawler.save_data_to_csv(",[116,2284,2285],{"class":250},"\"news_results.csv\"",[116,2287,1242],{"class":126},[17,2289,2290,2291,2297],{},"นอกจากนี้เรายังใช้งาน directory brute force ผ่านเครื่องมือ dirsearch (",[2292,2293,2294],"a",{"href":2294,"rel":2295},"https:\u002F\u002Fgithub.com\u002Fmaurosoria\u002Fdirsearch",[2296],"nofollow",")",[17,2299,2300],{},"ซึ่งเราจะทำการออกแบบประมาณนี้",[17,2302,2303],{},[2304,2305],"img",{"alt":104,"src":2306,"width":2307,"height":2308},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-00.webp",868,473,[17,2310,2311],{},"หลังจากได้เครื่องมือทั้ง 2 อย่างแล้ว ถึงเวลาที่เราจะเอาไปเชื่อมต่อกับ AI",[17,2313,2314],{},"สำหรับการทำ Agentic AI ผมเลือกใช้ไลบรารี pydantic_ai ที่รองรับ Gemini และใช้งานง่าย",[17,2316,2317],{},"มาเริ่มต้นเขียน agent กันดูครับ",[17,2319,2320],{},[2304,2321],{"alt":104,"src":2322,"width":2323,"height":2324},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-01.webp",1872,840,[17,2326,2327],{},"และเพิ่มในส่วน dirsearch เพื่อทำ directory brute force",[17,2329,2330],{},[2304,2331],{"alt":104,"src":2332,"width":2333,"height":2334},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-02.webp",1628,950,[17,2336,2337,2338],{},"ต่อมาเราจะทดสอบเรียกใช้งาน class ที่สร้างขึ้นโดยทดสอบกับเว็บไซต์ ",[2292,2339,2341],{"href":2340},"\u002F","https:\u002F\u002Fincognitolab.com",[17,2343,2344],{},[2304,2345],{"alt":104,"src":2346,"width":2347,"height":2348},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-03.webp",1687,607,[17,2350,2351],{},"ดูดีใช้ได้เลย ต่อไปเรามาพัฒนา tool ของเราให้มีความสามารถมากขึ้นด้วยการเพิ่ม feature ดังนี้",[53,2353,2354,2357,2360],{},[56,2355,2356],{},"เก็บข้อมูล HTTP security header",[56,2358,2359],{},"เก็บข้อมูล Service port ที่เปิดใช้งานและเวอร์ชันของแต่ละบริการ",[56,2361,2362],{},"รวบรวมและวิเคราะห์ข้อมูลทั้งหมดเพื่อค้นหาช่องโหว่ที่อาจเกิดขึ้น",[45,2364,2366],{"id":2365},"service-port-service-version-และ-http-security-header","Service Port, Service Version และ HTTP Security Header",[17,2368,2369],{},"เมื่อเราออกแบบโครงสร้าง ก็น่าจะได้หน้าตาประมาณนี้ แม้ว่าเรายังไม่รู้ว่าผลลัพธ์จริงจะออกมาเป็นอย่างไร แต่เราจะกำหนดให้แสดงผลเป็น HTML ที่สวยงามไว้ก่อน 555",[17,2371,2372],{},[2304,2373],{"alt":104,"src":2374,"width":2375,"height":2376},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-04.webp",1037,495,[17,2378,2379],{},"โดยโค้ดของ agent ที่เพิ่มเข้ามาจะเป็นดังนี้",[17,2381,2382],{},[21,2383,2384],{},"Header Collector",[17,2386,2387,2388,2392],{},"ในส่วนนี้จะทำการเรียกใช้งาน service HTTP security header จากเว็บไซต์พันธมิตรของเราคือ ",[2292,2389,2390],{"href":2390,"rel":2391},"https:\u002F\u002Fhs.iamthana.com\u002F",[2296]," โดยมีตัวอย่างการตรวจสอบ header ดังนี้",[17,2394,2395,2396],{},"ตัวอย่างการเรียกใช้งาน: ",[2292,2397,2398],{"href":2398,"rel":2399},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fobservatory",[2296],[17,2401,2402],{},"ผลลัพธ์",[17,2404,2405],{},[2304,2406],{"alt":104,"src":2407,"width":2408,"height":2409},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-05.webp",1230,1348,[17,2411,2412],{},"คร่าวนี้มาผนวกรวมกับ agent ของเรา",[17,2414,2415],{},[2304,2416],{"alt":104,"src":2417,"width":2418,"height":2419},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-06.webp",1065,1192,[17,2421,2422],{},[21,2423,2424],{},"Service Port และ Service Version",[17,2426,2427],{},"สำหรับการตรวจสอบ Service Port และ Service Version เราสามารถใช้งาน nmap scan",[17,2429,2430],{},[2292,2431,2432],{"href":2432,"rel":2433},"https:\u002F\u002Fnmap.org\u002F",[2296],[17,2435,2436],{},"ซึ่งเป็นเครื่องมือที่ออกแบบมาเพื่องานนี้โดยเฉพาะ เราจึงสามารถผนวกเข้ากับ agent ได้ดังนี้",[17,2438,2439],{},[2304,2440],{"alt":104,"src":2441,"width":2442,"height":2443},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-07.webp",1730,938,[17,2445,2446],{},[2304,2447],{"alt":104,"src":2448,"width":2449,"height":2450},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-08.webp",1576,1094,[45,2452,2454],{"id":2453},"analyzer-agent",[21,2455,2456],{},"Analyzer Ag﻿ent",[17,2458,2459],{},"ในส่วนนี้เราจะใช้ข้อมูลจากส่วนก่อนหน้ามาให้ AI วิเคราะห์ทั้งหมด เพื่อค้นหา attack surface และ potential vulnerability ที่อาจเกิดขึ้น เราไม่มีทางรู้เลยว่าผลลัพธ์ที่ได้จะออกมาแย่มากหรือจะออกมาดีเยี่ยม โดยโค้ดส่วนใหญ่จะประกอบไปด้วย",[17,2461,2462],{},[2304,2463],{"alt":104,"src":2464,"width":2465,"height":2466},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-09.webp",1948,1150,[17,2468,2469],{},"และส่วน export HTML",[17,2471,2472],{},[2304,2473],{"alt":104,"src":2474,"width":2475,"height":2476},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-10.webp",1169,981,[45,2478,2480],{"id":2479},"test-phase","Test Phase",[17,2482,2483],{},"หลังจากเตรียมทุกอย่างเรียบร้อยแล้ว ถึงเวลาทดสอบกัน จากผลลัพธ์ที่ทดลองพบว่าสามารถ run agent ในการรวบรวมข้อมูลได้ตามที่ต้องการ",[17,2485,2486],{},[2304,2487],{"alt":104,"src":2488,"width":2489,"height":2490},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-11.webp",1196,451,[45,2492,2494],{"id":2493},"review-phase","Review Phase",[17,2496,2497],{},"เมื่อเรามาดูข้อมูลวิเคราะห์ที่ได้จาก Analyzer Agent แล้วพบว่าผลลัพธ์ที่ได้ยังไม่น่าพอใจเท่าที่ควร",[17,2499,2500],{},[2304,2501],{"alt":104,"src":2502,"width":2503,"height":2504},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-12.webp",1265,1105,[17,2506,2507],{},"ในส่วนการวิเคราะห์ HTTP Security Header นั้น สามารถระบุผลกระทบด้านความปลอดภัยได้ดี แต่คำแนะนำในการแก้ไขยังขาดความชัดเจนและไม่สามารถนำไปปฏิบัติได้ทันที",[17,2509,2510],{},[2304,2511],{"alt":104,"src":2512,"width":2513,"height":2514},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-13.webp",1219,1042,[17,2516,2517],{},"ในส่วนของ port scan พบว่า agent สามารถตรวจพบ service port เว็บเซิร์ฟเวอร์กำลังทำงานอยู่ได้",[17,2519,2520],{},[2304,2521],{"alt":104,"src":2522,"width":2523,"height":2524},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-14.webp",1242,879,[17,2526,2527],{},"เมื่อทำการตรวจสอบในส่วนของ directories พบว่าไม่สามารถค้นพบ directories ใดๆ จากการใช้ dirsearch",[17,2529,2530],{},[2304,2531],{"alt":104,"src":2532,"width":2533,"height":2534},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-15.webp",493,207,[17,2536,2537],{},"พบเจอแต่ internal link จากการทำ web crawling เท่านั้น",[17,2539,2540],{},[2304,2541],{"alt":104,"src":2542,"width":2543,"height":1540},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-16.webp",1159,[17,2545,2546],{},"และบทสรุปส่งท้ายที่ได้พบว่า Analyzer Agent สามารถวิเคราะห์ข้อมูลทั้งหมดและเขียนสรุปในมุมมองด้าน cybersecurity ได้ดี อ่านเข้าใจง่าย แต่ยังมีข้อบกพร่องในการประเมินค่า severity score",[17,2548,2549],{},[2304,2550],{"alt":104,"src":2551,"width":2552,"height":2553},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-17.webp",1261,1028,[45,2555,2557],{"id":2556},"optimize-phase","Optimize phase",[17,2559,2560],{},"จากผลลัพธ์ที่ได้รับมา เราทำการปรับปรุง 4 อย่างดังนี้",[2562,2563,2564,2567,2570],"ol",{},[56,2565,2566],{},"แก้ไขให้นำ URL internal link มารวมในการค้นหาไดเรกทอรี",[56,2568,2569],{},"เพิ่ม agent ให้ตรวจสอบผลจาก Analyzer Agent อีกครั้ง หากไม่ถูกต้องให้วิเคราะห์ใหม่",[56,2571,2572],{},"ใช้ CVSS score ในการประเมินระดับความรุนแรง",[17,2574,2575],{},"จากการปรับปรุงดังกล่าว คาดว่าจะได้ผลลัพธ์ที่ดีขึ้น",[17,2577,2578],{},[2304,2579],{"alt":104,"src":2580,"width":2581,"height":2582},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-18.webp",1791,637,[17,2584,2585],{},"ลองทำการทดสอบที่ Inconitolab อีกที",[17,2587,2588],{},[2304,2589],{"alt":104,"src":2590,"width":2591,"height":2592},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-19.webp",1409,747,[17,2594,2595,2596],{},"การแก้ไข output ในส่วนของ ",[21,2597,2598],{},"Directory Enumeration เป็นไปได้ด้วยดี",[17,2600,2601],{},[2304,2602],{"alt":104,"src":2603,"width":2604,"height":2605},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-20.webp",1060,714,[17,2607,2608],{},[2304,2609],{"alt":104,"src":2610,"width":2611,"height":1948},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-21.webp",999,[17,2613,2614],{},"ในส่วนของบทวิเคราะห์ที่ใช้ Agentic AI 2 ตัวในการแก้ไขและวิเคราะห์ร่วมกัน โดยใช้ CVSS ในการประเมินพบว่า AI สามารถประเมินความเสี่ยงได้ดีขึ้นและมีหลักการชัดเจนมากขึ้น",[17,2616,2617],{},[2304,2618],{"alt":104,"src":2619,"width":2620,"height":2621},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-22.webp",1271,1307,[45,2623,2625],{"id":2624},"final-actions",[21,2626,2627],{},"Final Actions",[17,2629,2630],{},"สุดท้ายเราได้นำผลลัพธ์มาปรับปรุงการแสดงผลใหม่ โดยให้ Agentic AI รับข้อมูลจาก review agent มาสร้างเป็น dashboard พร้อมสรุปผลที่สวยงาม และแสดงในรูปแบบ markdown",[17,2632,2633],{},"การปรับปรุงนี้ช่วยให้ผู้ใช้งานสามารถอ่านและทำความเข้าใจรายงานได้ง่ายขึ้น",[17,2635,2636],{},[2304,2637],{"alt":104,"src":2638,"width":2639,"height":2640},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-23.webp",1668,528,[17,2642,2643],{},"โดยผลลัพท์หน้าตาประมาณนี้ครับ",[17,2645,2646],{},[2304,2647],{"alt":104,"src":2648,"width":2649,"height":2650},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-24.webp",2354,1384,[17,2652,2653],{},[2304,2654],{"alt":104,"src":2655,"width":2656,"height":2657},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-25.webp",2182,1044,[17,2659,2660],{},[2304,2661],{"alt":104,"src":2662,"width":2663,"height":2664},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-26.webp",2224,1686,[17,2666,2667],{},[2304,2668],{"alt":104,"src":2669,"width":2670,"height":2671},"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Fimage-27.webp",2270,1302,[45,2673,2675],{"id":2674},"what-next","What Next",[17,2677,2678],{},"ในบทความต่อไป เราจะพัฒนา tool ของเราให้แข็งแกร่งขึ้นด้วย web application scan และ VA tool เพื่อให้ได้ผลลัพธ์ที่ครอบคลุมเทียบเท่าเครื่องมือ automated testing ทั่วไป นอกจากนี้ เราจะเพิ่ม agentic AI เข้าไปเพื่อให้เข้าใจ business logic ของเว็บไซต์เป้าหมายได้ดียิ่งขึ้น",[45,2680,2682],{"id":2681},"summary","Summary",[17,2684,2685],{},"สุดท้ายนี้ การใช้ Agentic AI ในงานด้าน Cybersecurity ได้แสดงให้เห็นถึงการทำงานที่น่าสนใจ โดยเริ่มจากการเก็บข้อมูลพื้นฐาน เช่น URL, Path, Service Port และ HTTP Security Header ด้วยเครื่องมืออย่าง Web Crawling, Directory Brute Force และ Nmap พร้อมทั้งการพัฒนา Agentic AI ที่สามารถวิเคราะห์ข้อมูลเพื่อค้นหา attack surface และช่องโหว่ที่อาจเกิดขึ้น",[17,2687,2688],{},"แม้ว่าการทดสอบจะพบข้อผิดพลาด เช่น การตรวจจับข้อมูลที่ไม่ครบถ้วนและการวิเคราะห์ที่ยังไม่แม่นยำ แต่ก็แสดงให้เห็นศักยภาพของ AI ในการช่วยลดภาระงานและพัฒนาการวิเคราะห์ด้านความปลอดภัย อย่างไรก็ตาม ยังจำเป็นต้องปรับปรุงเครื่องมือและกระบวนการเพิ่มเติมเพื่อให้เหมาะสมกับการใช้งานจริง",[17,2690,2691],{},"สำหรับการนำไปใช้งานจริง จำเป็นต้องนำโมเดลมา fine-tuning และกำหนดกรอบการใช้งานให้ชัดเจนยิ่งขึ้น",[17,2693,2694],{},"หากสนใจเนื้อหาเพิ่มเติมในแนวนี้ สามารถติดตาม incognitolab ได้เลยครับ",[2696,2697,2698],"style",{},"html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sqxcx, html code.shiki .sqxcx{--shiki-default:#E36209}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":104,"searchDepth":130,"depth":130,"links":2700},[2701],{"id":14,"depth":130,"text":15},"2025-05-06","Agentic AI ที่แบ่งหน้าที่และตรวจสอบกันเองได้ เอามาใช้กับงาน cybersecurity ตรงไหนได้บ้าง และเปลี่ยนวิธีทำงานของทีมไปอย่างไร",false,"md",null,"\u002Fimages\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity\u002Ffull.png","th",{},"\u002Fblogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity",{"title":6,"description":2703},"blogs\u002F2025-05-06-agentic-ai-work-flow-in-cybersecurity",[2714,2715,2716],"ai-security","pentest","red-teaming","ARTICLES","Vjb8J9Z-yReW4nkjDOhF8EMrMz_H_HDR7tqSSFiWoI8",[2720,2730,2740],{"id":2721,"link":2722,"title":2723,"description":2724,"image":2725,"date":2726,"type":2717,"author":2727,"tags":2728},"content\u002Fblogs\u002F2026-09-17-owasp-llm-security-2026.md","owasp-llm-security-2026","OWASP Top 10 for LLM 2026: เมื่อ AI Agents และ RAG กลายเป็น Attack Surface ใหม่","ภาพรวมของ OWASP Top 10 for LLM ฉบับ 2026 เจาะ Excessive Agency, ช่องโหว่ RAG และ Tool Poisoning พร้อมตัวอย่าง Indirect Prompt Injection และแนวทาง Secure by Design","\u002Fimages\u002Fblogs\u002F2026-09-17-owasp-llm-security-2026\u002Fimage-20260917-041035.424Z-3136.webp","2026-09-17","Thana Tingprasom",[2714,2729,2715],"vulnerability",{"id":2731,"link":2732,"title":2733,"description":2734,"image":2735,"date":2736,"type":2717,"author":2737,"tags":2738},"content\u002Fblogs\u002F2026-08-25-certighost-cve-2026-54121.md","certighost-cve-2026-54121","วิเคราะห์ CVE-2026-54121 - CertiGhost","แค่ domain user สิทธิ์ต่ำ ๆ ก็ยึด domain ได้? มาดูกันว่า CertiGhost (CVE-2026-54121) ใช้ช่องโหว่ใน AD CS ปลอมตัวเป็น DC ได้ยังไง","\u002Fimages\u002Fblogs\u002F2026-08-25-certighost-cve-2026-54121\u002Fimage-20260917-042953.815Z-320.webp","2026-08-25","Suppawej Kerdphol",[2715,2716,2739,2729],"active-directory",{"id":2741,"link":2742,"title":2743,"description":2744,"image":2745,"date":2746,"type":2717,"author":2747,"tags":2748},"content\u002Fblogs\u002F2026-08-10-ker-delg-pt1.md","ker-delg-pt1","Kerberos Delegation Attacks Part 1: Unconstrained Delegation","Kerberos Delegation ถูกสร้างมาเพื่อรองรับ multi-tier application แต่ trust relationship ที่ทรงพลังของมันก็เปิดช่องให้ attacker ปลอมเป็นผู้ใช้และทำ lateral movement ได้ถ้าตั้งค่าผิด","\u002Fimages\u002Fblogs\u002F2026-08-10-ker-delg-pt1\u002Fimage-20260803-161404.426Z-1207.png","2026-08-10","Wisarud Wongta",[2715,2716,2739,2749,2750],"kerberos","windows-security",[],1791516129422]